diff --git a/api/src/main/java/org/apache/flink/agents/api/EventType.java b/api/src/main/java/org/apache/flink/agents/api/EventType.java new file mode 100644 index 000000000..f486a6d0e --- /dev/null +++ b/api/src/main/java/org/apache/flink/agents/api/EventType.java @@ -0,0 +1,44 @@ +/* + * 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.flink.agents.api; + +/** + * Compile-time constants for built-in event types, sourced from each {@code XxxEvent.EVENT_TYPE}. + * + *

Usage: {@code @Action(EventType.InputEvent)}. + */ +public final class EventType { + + public static final String InputEvent = org.apache.flink.agents.api.InputEvent.EVENT_TYPE; + public static final String OutputEvent = org.apache.flink.agents.api.OutputEvent.EVENT_TYPE; + public static final String ChatRequestEvent = + org.apache.flink.agents.api.event.ChatRequestEvent.EVENT_TYPE; + public static final String ChatResponseEvent = + org.apache.flink.agents.api.event.ChatResponseEvent.EVENT_TYPE; + public static final String ToolRequestEvent = + org.apache.flink.agents.api.event.ToolRequestEvent.EVENT_TYPE; + public static final String ToolResponseEvent = + org.apache.flink.agents.api.event.ToolResponseEvent.EVENT_TYPE; + public static final String ContextRetrievalRequestEvent = + org.apache.flink.agents.api.event.ContextRetrievalRequestEvent.EVENT_TYPE; + public static final String ContextRetrievalResponseEvent = + org.apache.flink.agents.api.event.ContextRetrievalResponseEvent.EVENT_TYPE; + + private EventType() {} +} diff --git a/api/src/main/java/org/apache/flink/agents/api/agents/Agent.java b/api/src/main/java/org/apache/flink/agents/api/agents/Agent.java index f73372488..18a7869b7 100644 --- a/api/src/main/java/org/apache/flink/agents/api/agents/Agent.java +++ b/api/src/main/java/org/apache/flink/agents/api/agents/Agent.java @@ -56,43 +56,47 @@ public Map> getResources() { /** * Add action to agent. * - * @param eventTypes The event type strings this action listens to. + * @param triggerConditions Trigger condition strings — each is either an event-type name or a + * future condition-expression form. * @param method The method of this action, should be static method. * @param config The optional config can be used by this action. */ public Agent addAction( - String[] eventTypes, Method method, @Nullable Map config) { - return addAction(method.getName(), eventTypes, JavaFunction.fromMethod(method), config); + String[] triggerConditions, Method method, @Nullable Map config) { + return addAction( + method.getName(), triggerConditions, JavaFunction.fromMethod(method), config); } /** * Add action to agent. * - * @param eventTypes The event type strings this action listens to. + * @param triggerConditions Trigger condition strings — each is either an event-type name or a + * future condition-expression form. * @param method The method of this action, should be static method. */ - public Agent addAction(String[] eventTypes, Method method) { - return addAction(eventTypes, method, null); + public Agent addAction(String[] triggerConditions, Method method) { + return addAction(triggerConditions, method, null); } /** * Add action to agent. * * @param name The action name. Must be unique within this agent. - * @param eventTypes The event type strings this action listens to. + * @param triggerConditions Trigger condition strings — each is either an event-type name or a + * future condition-expression form. * @param function The api-layer function descriptor; will be promoted to a plan-layer * executable at {@code AgentPlan} construction. * @param config Optional config for this action. */ public Agent addAction( String name, - String[] eventTypes, + String[] triggerConditions, Function function, @Nullable Map config) { if (actions.containsKey(name)) { throw new IllegalArgumentException(String.format("Action %s already defined.", name)); } - actions.put(name, new Tuple3<>(eventTypes, function, config)); + actions.put(name, new Tuple3<>(triggerConditions, function, config)); return this; } diff --git a/api/src/main/java/org/apache/flink/agents/api/agents/ReActAgent.java b/api/src/main/java/org/apache/flink/agents/api/agents/ReActAgent.java index 088f3efd0..10ed457e0 100644 --- a/api/src/main/java/org/apache/flink/agents/api/agents/ReActAgent.java +++ b/api/src/main/java/org/apache/flink/agents/api/agents/ReActAgent.java @@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.ClassUtils; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.annotation.Action; @@ -168,7 +169,7 @@ public static void startAction(Event event, RunnerContext ctx) { ctx.sendEvent(new ChatRequestEvent(DEFAULT_CHAT_MODEL, inputMessages, outputSchema)); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void stopAction(Event event, RunnerContext ctx) { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); ChatMessage response = chatResponse.getResponse(); diff --git a/api/src/main/java/org/apache/flink/agents/api/annotation/Action.java b/api/src/main/java/org/apache/flink/agents/api/annotation/Action.java index fd7f62c92..49084255b 100644 --- a/api/src/main/java/org/apache/flink/agents/api/annotation/Action.java +++ b/api/src/main/java/org/apache/flink/agents/api/annotation/Action.java @@ -24,23 +24,24 @@ import java.lang.annotation.Target; /** - * Annotation for marking a method as an agent action. + * Marks a method as an agent action triggered by matching events. * - *

This annotation specifies which event types the action should respond to. The annotated method - * will be triggered when any of the specified event types occur. + *

Each {@link #value()} entry is an event type name string. Use the {@code EVENT_TYPE} constants + * on built-in event classes, the {@link org.apache.flink.agents.api.EventType} constants, or plain + * strings for custom events. Multiple entries combine with OR. * - *

Events are specified as type strings via {@link #listenEventTypes()}. Use the {@code - * EVENT_TYPE} constants on built-in event classes for standard events, or plain strings for custom - * events. + *

{@code
+ * // Built-in event type via the EventType constant
+ * @Action(EventType.InputEvent)
  *
- * 

Example usage: + * // Equivalent via the legacy class constant + * @Action(InputEvent.EVENT_TYPE) * - *

{@code
- * @Action(listenEventTypes = {InputEvent.EVENT_TYPE})
- * public void handleInput(Event event, RunnerContext ctx) { ... }
+ * // User-defined event type
+ * @Action("MyCustomEvent")
  *
- * @Action(listenEventTypes = {InputEvent.EVENT_TYPE, "MyCustomEvent"})
- * public void handleMultiple(Event event, RunnerContext ctx) { ... }
+ * // Multiple types (OR semantics)
+ * @Action({EventType.InputEvent, "MyCustomEvent"})
  * }
* *

For a cross-language action, set {@link #target()} to a {@link PythonFunction} with a @@ -49,7 +50,7 @@ * *

{@code
  * @Action(
- *     listenEventTypes = {InputEvent.EVENT_TYPE},
+ *     value = EventType.InputEvent,
  *     target = @PythonFunction(module = "my_pkg.handlers", qualname = "handle_input"))
  * public void handleInput(Event event, RunnerContext ctx) {
  *     throw new UnsupportedOperationException("cross-language stub");
@@ -60,11 +61,11 @@
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Action {
     /**
-     * List of event type strings that this action should respond to.
-     *
-     * @return Array of event type strings
+     * Event type name strings; multiple entries have OR semantics. Named {@code value} (not {@code
+     * triggerConditions}) to enable the {@code @Action({...})} shorthand (JLS §9.7.3); corresponds
+     * to Python's {@code *trigger_conditions}.
      */
-    String[] listenEventTypes();
+    String[] value();
 
     /**
      * Cross-language target. When {@link PythonFunction#module()} is non-empty, dispatch routes to
diff --git a/api/src/main/java/org/apache/flink/agents/api/yaml/YamlLoader.java b/api/src/main/java/org/apache/flink/agents/api/yaml/YamlLoader.java
index 3de375b75..6f7359da5 100644
--- a/api/src/main/java/org/apache/flink/agents/api/yaml/YamlLoader.java
+++ b/api/src/main/java/org/apache/flink/agents/api/yaml/YamlLoader.java
@@ -430,9 +430,11 @@ static Function resolveActionFunction(ActionSpec action) {
     /** Register an action on the agent with event aliases resolved. */
     static void addActionToAgent(Agent agent, ActionSpec action) {
         Function fn = resolveActionFunction(action);
-        String[] events =
-                action.getListenTo().stream().map(Aliases::resolveEventType).toArray(String[]::new);
+        String[] triggerConditions =
+                action.getTriggerConditions().stream()
+                        .map(Aliases::resolveEventType)
+                        .toArray(String[]::new);
         Map config = action.getConfig();
-        agent.addAction(action.getName(), events, fn, config);
+        agent.addAction(action.getName(), triggerConditions, fn, config);
     }
 }
diff --git a/api/src/main/java/org/apache/flink/agents/api/yaml/spec/ActionSpec.java b/api/src/main/java/org/apache/flink/agents/api/yaml/spec/ActionSpec.java
index 4a8b07cf6..7a0280be5 100644
--- a/api/src/main/java/org/apache/flink/agents/api/yaml/spec/ActionSpec.java
+++ b/api/src/main/java/org/apache/flink/agents/api/yaml/spec/ActionSpec.java
@@ -26,12 +26,17 @@
 import java.util.List;
 import java.util.Map;
 
-/** Action referencing a user function plus the event types it listens to. */
+/**
+ * Action referencing a user function plus its trigger conditions.
+ *
+ * 

Each entry in {@code trigger_conditions} is either an event-type name (bare identifier) or a + * future condition-expression form — the runtime classifies the string when it loads the plan. + */ @JsonIgnoreProperties(ignoreUnknown = false) public final class ActionSpec { private final String name; private final String function; - private final List listenTo; + private final List triggerConditions; private final Map config; private final Language type; @@ -39,15 +44,16 @@ public final class ActionSpec { public ActionSpec( @JsonProperty(value = "name", required = true) String name, @JsonProperty("function") String function, - @JsonProperty(value = "listen_to", required = true) List listenTo, + @JsonProperty(value = "trigger_conditions", required = true) + List triggerConditions, @JsonProperty("config") Map config, @JsonProperty("type") Language type) { - if (listenTo == null || listenTo.isEmpty()) { - throw new IllegalArgumentException("listen_to must not be empty"); + if (triggerConditions == null || triggerConditions.isEmpty()) { + throw new IllegalArgumentException("trigger_conditions must not be empty"); } this.name = name; this.function = function; - this.listenTo = listenTo; + this.triggerConditions = triggerConditions; this.config = config; this.type = type; } @@ -60,8 +66,8 @@ public String getFunction() { return function; } - public List getListenTo() { - return listenTo; + public List getTriggerConditions() { + return triggerConditions; } public Map getConfig() { diff --git a/api/src/test/java/org/apache/flink/agents/api/EventTypeTest.java b/api/src/test/java/org/apache/flink/agents/api/EventTypeTest.java new file mode 100644 index 000000000..4ac5aa728 --- /dev/null +++ b/api/src/test/java/org/apache/flink/agents/api/EventTypeTest.java @@ -0,0 +1,47 @@ +/* + * 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.flink.agents.api; + +import org.apache.flink.agents.api.event.ChatRequestEvent; +import org.apache.flink.agents.api.event.ChatResponseEvent; +import org.apache.flink.agents.api.event.ContextRetrievalRequestEvent; +import org.apache.flink.agents.api.event.ContextRetrievalResponseEvent; +import org.apache.flink.agents.api.event.ToolRequestEvent; +import org.apache.flink.agents.api.event.ToolResponseEvent; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** Tests for {@link EventType}. */ +class EventTypeTest { + + @Test + void builtInConstantsMatchEventClassConstants() { + assertEquals(InputEvent.EVENT_TYPE, EventType.InputEvent); + assertEquals(OutputEvent.EVENT_TYPE, EventType.OutputEvent); + assertEquals(ChatRequestEvent.EVENT_TYPE, EventType.ChatRequestEvent); + assertEquals(ChatResponseEvent.EVENT_TYPE, EventType.ChatResponseEvent); + assertEquals(ToolRequestEvent.EVENT_TYPE, EventType.ToolRequestEvent); + assertEquals(ToolResponseEvent.EVENT_TYPE, EventType.ToolResponseEvent); + assertEquals( + ContextRetrievalRequestEvent.EVENT_TYPE, EventType.ContextRetrievalRequestEvent); + assertEquals( + ContextRetrievalResponseEvent.EVENT_TYPE, EventType.ContextRetrievalResponseEvent); + } +} diff --git a/api/src/test/java/org/apache/flink/agents/api/yaml/YamlLoaderBuildAgentsTest.java b/api/src/test/java/org/apache/flink/agents/api/yaml/YamlLoaderBuildAgentsTest.java index 802622c21..95b3509ef 100644 --- a/api/src/test/java/org/apache/flink/agents/api/yaml/YamlLoaderBuildAgentsTest.java +++ b/api/src/test/java/org/apache/flink/agents/api/yaml/YamlLoaderBuildAgentsTest.java @@ -147,7 +147,7 @@ void actionDefaultsToPython(@TempDir Path tmp) throws Exception { + " actions:\n" + " - name: act\n" + " function: pkg.mod:fn\n" - + " listen_to: [input]\n"); + + " trigger_conditions: [input]\n"); LoadedFile out = YamlLoader.buildAgents(file); Tuple3> entry = out.getAgents().get("a").getActions().get("act"); diff --git a/api/src/test/java/org/apache/flink/agents/api/yaml/spec/ActionSpecTest.java b/api/src/test/java/org/apache/flink/agents/api/yaml/spec/ActionSpecTest.java index 3143f5623..6b7366aec 100644 --- a/api/src/test/java/org/apache/flink/agents/api/yaml/spec/ActionSpecTest.java +++ b/api/src/test/java/org/apache/flink/agents/api/yaml/spec/ActionSpecTest.java @@ -32,29 +32,31 @@ class ActionSpecTest { @Test void minimal() throws Exception { ActionSpec spec = - M.readValue("name: a\nfunction: pkg:fn\nlisten_to: [input]\n", ActionSpec.class); + M.readValue( + "name: a\nfunction: pkg:fn\ntrigger_conditions: [input]\n", + ActionSpec.class); assertThat(spec.getName()).isEqualTo("a"); assertThat(spec.getFunction()).isEqualTo("pkg:fn"); - assertThat(spec.getListenTo()).containsExactly("input"); + assertThat(spec.getTriggerConditions()).containsExactly("input"); assertThat(spec.getConfig()).isNull(); assertThat(spec.getType()).isNull(); } @Test - void rejectsEmptyListenTo() { + void rejectsEmptyTriggerConditions() { assertThatThrownBy( () -> M.readValue( - "name: a\nfunction: x:y\nlisten_to: []\n", + "name: a\nfunction: x:y\ntrigger_conditions: []\n", ActionSpec.class)) - .hasMessageContaining("listen_to"); + .hasMessageContaining("trigger_conditions"); } @Test void typeJava() throws Exception { ActionSpec spec = M.readValue( - "name: a\nfunction: X:m\nlisten_to: [input]\ntype: java\n", + "name: a\nfunction: X:m\ntrigger_conditions: [input]\ntype: java\n", ActionSpec.class); assertThat(spec.getType()).isEqualTo(Language.JAVA); } @@ -64,7 +66,7 @@ void rejectsUnknownProperty() { assertThatThrownBy( () -> M.readValue( - "name: a\nfunction: x:y\nlisten_to: [input]\nextra: 1\n", + "name: a\nfunction: x:y\ntrigger_conditions: [input]\nextra: 1\n", ActionSpec.class)) .hasMessageContaining("extra"); } diff --git a/api/src/test/java/org/apache/flink/agents/api/yaml/spec/AgentSpecTest.java b/api/src/test/java/org/apache/flink/agents/api/yaml/spec/AgentSpecTest.java index a7840ed74..1c6fdb2c6 100644 --- a/api/src/test/java/org/apache/flink/agents/api/yaml/spec/AgentSpecTest.java +++ b/api/src/test/java/org/apache/flink/agents/api/yaml/spec/AgentSpecTest.java @@ -44,7 +44,7 @@ void actionEntryCanBeStringOrFullSpec() throws Exception { + " - shared_one\n" + " - name: own\n" + " function: pkg:fn\n" - + " listen_to: [input]\n"; + + " trigger_conditions: [input]\n"; AgentSpec spec = M.readValue(yaml, AgentSpec.class); assertThat(spec.getActions()).hasSize(2); assertThat(spec.getActions().get(0).isReference()).isTrue(); diff --git a/api/src/test/java/org/apache/flink/agents/api/yaml/spec/YamlAgentsDocumentTest.java b/api/src/test/java/org/apache/flink/agents/api/yaml/spec/YamlAgentsDocumentTest.java index d7e7604e5..67ab6fbf5 100644 --- a/api/src/test/java/org/apache/flink/agents/api/yaml/spec/YamlAgentsDocumentTest.java +++ b/api/src/test/java/org/apache/flink/agents/api/yaml/spec/YamlAgentsDocumentTest.java @@ -40,7 +40,7 @@ void sharedSectionsAtFileLevel() throws Exception { String yaml = "agents:\n - name: a\n" + "chat_model_connections:\n - name: shared\n clazz: x.Y\n" - + "actions:\n - name: shared_a\n function: pkg:fn\n listen_to: [input]\n"; + + "actions:\n - name: shared_a\n function: pkg:fn\n trigger_conditions: [input]\n"; YamlAgentsDocument doc = M.readValue(yaml, YamlAgentsDocument.class); assertThat(doc.getChatModelConnections()).hasSize(1); assertThat(doc.getActions()).hasSize(1); diff --git a/api/src/test/resources/yaml/fixtures/dup_agent.yaml b/api/src/test/resources/yaml/fixtures/dup_agent.yaml index d3b340b4b..eaae8c78a 100644 --- a/api/src/test/resources/yaml/fixtures/dup_agent.yaml +++ b/api/src/test/resources/yaml/fixtures/dup_agent.yaml @@ -4,10 +4,10 @@ agents: - name: increment function: org.apache.flink.agents.api.yaml.LoaderTargets:increment type: java - listen_to: [input] + trigger_conditions: [input] - name: dup actions: - name: decrement function: org.apache.flink.agents.api.yaml.LoaderTargets:decrement type: java - listen_to: [input] + trigger_conditions: [input] diff --git a/api/src/test/resources/yaml/fixtures/multi_agent.yaml b/api/src/test/resources/yaml/fixtures/multi_agent.yaml index b2d4fde78..2b666cc6d 100644 --- a/api/src/test/resources/yaml/fixtures/multi_agent.yaml +++ b/api/src/test/resources/yaml/fixtures/multi_agent.yaml @@ -4,10 +4,10 @@ agents: - name: increment function: org.apache.flink.agents.api.yaml.LoaderTargets:increment type: java - listen_to: [input] + trigger_conditions: [input] - name: a2 actions: - name: decrement function: org.apache.flink.agents.api.yaml.LoaderTargets:decrement type: java - listen_to: [input] + trigger_conditions: [input] diff --git a/api/src/test/resources/yaml/fixtures/multi_file_a.yaml b/api/src/test/resources/yaml/fixtures/multi_file_a.yaml index d9c29439a..4b421ce0a 100644 --- a/api/src/test/resources/yaml/fixtures/multi_file_a.yaml +++ b/api/src/test/resources/yaml/fixtures/multi_file_a.yaml @@ -4,7 +4,7 @@ agents: - name: increment function: org.apache.flink.agents.api.yaml.LoaderTargets:increment type: java - listen_to: [input] + trigger_conditions: [input] chat_model_connections: - name: conn_from_a clazz: ollama diff --git a/api/src/test/resources/yaml/fixtures/multi_file_b.yaml b/api/src/test/resources/yaml/fixtures/multi_file_b.yaml index d53c5b34e..ebba486a3 100644 --- a/api/src/test/resources/yaml/fixtures/multi_file_b.yaml +++ b/api/src/test/resources/yaml/fixtures/multi_file_b.yaml @@ -4,7 +4,7 @@ agents: - name: decrement function: org.apache.flink.agents.api.yaml.LoaderTargets:decrement type: java - listen_to: [input] + trigger_conditions: [input] chat_model_connections: - name: conn_from_b clazz: ollama diff --git a/api/src/test/resources/yaml/fixtures/single_agent.yaml b/api/src/test/resources/yaml/fixtures/single_agent.yaml index 8a497f675..4d2f50e14 100644 --- a/api/src/test/resources/yaml/fixtures/single_agent.yaml +++ b/api/src/test/resources/yaml/fixtures/single_agent.yaml @@ -4,4 +4,4 @@ agents: - name: increment function: org.apache.flink.agents.api.yaml.LoaderTargets:increment type: java - listen_to: [input] + trigger_conditions: [input] diff --git a/api/src/test/resources/yaml/fixtures/with_descriptors.yaml b/api/src/test/resources/yaml/fixtures/with_descriptors.yaml index 834819c75..c704726c6 100644 --- a/api/src/test/resources/yaml/fixtures/with_descriptors.yaml +++ b/api/src/test/resources/yaml/fixtures/with_descriptors.yaml @@ -4,11 +4,11 @@ agents: - name: increment function: org.apache.flink.agents.api.yaml.LoaderTargets:increment type: java - listen_to: [input] + trigger_conditions: [input] - name: decrement function: org.apache.flink.agents.api.yaml.LoaderTargets:decrement type: java - listen_to: [chat_response] + trigger_conditions: [chat_response] chat_model_connections: - name: ollama_conn clazz: ollama diff --git a/api/src/test/resources/yaml/fixtures/with_shared.yaml b/api/src/test/resources/yaml/fixtures/with_shared.yaml index 48581b549..adfcb910c 100644 --- a/api/src/test/resources/yaml/fixtures/with_shared.yaml +++ b/api/src/test/resources/yaml/fixtures/with_shared.yaml @@ -5,7 +5,7 @@ agents: - name: own_dec function: org.apache.flink.agents.api.yaml.LoaderTargets:decrement type: java - listen_to: [chat_response] + trigger_conditions: [chat_response] - name: a2 actions: - shared_inc @@ -20,4 +20,4 @@ actions: - name: shared_inc function: org.apache.flink.agents.api.yaml.LoaderTargets:increment type: java - listen_to: [input] + trigger_conditions: [input] diff --git a/api/src/test/resources/yaml/python-parity/yaml_test_agent.yaml b/api/src/test/resources/yaml/python-parity/yaml_test_agent.yaml index 6c29f5089..aa2e153c1 100644 --- a/api/src/test/resources/yaml/python-parity/yaml_test_agent.yaml +++ b/api/src/test/resources/yaml/python-parity/yaml_test_agent.yaml @@ -26,7 +26,7 @@ agents: actions: - name: process_input function: flink_agents.e2e_tests.e2e_tests_integration.yaml_test_actions:process_input - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response function: flink_agents.e2e_tests.e2e_tests_integration.yaml_test_actions:process_chat_response - listen_to: [chat_response] \ No newline at end of file + trigger_conditions: [chat_response] \ No newline at end of file diff --git a/docs/content/docs/development/chat_models.md b/docs/content/docs/development/chat_models.md index f6bfe7b77..c7b40ae05 100644 --- a/docs/content/docs/development/chat_models.md +++ b/docs/content/docs/development/chat_models.md @@ -80,7 +80,7 @@ class MyAgent(Agent): temperature=0.7 ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: input_event = InputEvent.from_event(event) @@ -93,7 +93,7 @@ class MyAgent(Agent): ChatRequestEvent(model="ollama_chat_model", messages=[user_message]) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_response(event: Event, ctx: RunnerContext) -> None: chat_response = ChatResponseEvent.from_event(event) @@ -121,7 +121,7 @@ public class MyAgent extends Agent { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); ChatMessage userMessage = @@ -129,7 +129,7 @@ public class MyAgent extends Agent { ctx.sendEvent(new ChatRequestEvent("ollamaChatModel", List.of(userMessage))); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processResponse(Event event, RunnerContext ctx) throws Exception { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); @@ -1178,7 +1178,7 @@ class MyAgent(Agent): extract_reasoning=True, ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: input_event = InputEvent.from_event(event) @@ -1191,7 +1191,7 @@ class MyAgent(Agent): ChatRequestEvent(model="java_chat_model", messages=[user_message]) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_response(event: Event, ctx: RunnerContext) -> None: chat_response = ChatResponseEvent.from_event(event) @@ -1237,7 +1237,7 @@ public class MyAgent extends Agent { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); ChatMessage userMessage = @@ -1245,7 +1245,7 @@ public class MyAgent extends Agent { ctx.sendEvent(new ChatRequestEvent("pythonChatModel", List.of(userMessage))); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processResponse(Event event, RunnerContext ctx) throws Exception { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); diff --git a/docs/content/docs/development/embedding_models.md b/docs/content/docs/development/embedding_models.md index 3646bcf52..a745dd154 100644 --- a/docs/content/docs/development/embedding_models.md +++ b/docs/content/docs/development/embedding_models.md @@ -129,7 +129,7 @@ class MyAgent(Agent): model="your-embedding-model-here" ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_text(event: Event, ctx: RunnerContext) -> None: # Get the embedding model from the runtime context @@ -165,7 +165,7 @@ public class MyAgent extends Agent { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processText(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); @@ -612,7 +612,7 @@ class MyAgent(Agent): model="nomic-embed-text" ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: # Use the Java embedding model from Python @@ -657,7 +657,7 @@ public class MyAgent extends Agent { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); // Use the Python embedding model from Java diff --git a/docs/content/docs/development/memory/long_term_memory.md b/docs/content/docs/development/memory/long_term_memory.md index eeb4c79d7..46ffc3ac6 100644 --- a/docs/content/docs/development/memory/long_term_memory.md +++ b/docs/content/docs/development/memory/long_term_memory.md @@ -148,7 +148,7 @@ from flink_agents.api.decorators import action from flink_agents.api.events.event import InputEvent, Event from flink_agents.api.runner_context import RunnerContext -@action(InputEvent.EVENT_TYPE) +@action(EventType.InputEvent) @staticmethod def process_event(event: Event, ctx: RunnerContext) -> None: ltm = ctx.long_term_memory @@ -162,7 +162,7 @@ def process_event(event: Event, ctx: RunnerContext) -> None: {{< tab "Java" >}} ```java -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) +@Action(EventType.InputEvent) public static void processEvent(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); BaseLongTermMemory ltm = ctx.getLongTermMemory(); @@ -464,7 +464,7 @@ from flink_agents.api.runner_context import RunnerContext class PersonalizedAssistant: - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_event(event: Event, ctx: RunnerContext) -> None: """Respond to user using long-term memory.""" @@ -501,7 +501,7 @@ agents_config.set(LongTermMemoryOptions.Mem0.VECTOR_STORE, "my_vector_store") {{< tab "Java" >}} ```java -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) +@Action(EventType.InputEvent) public static void processEvent(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); BaseLongTermMemory ltm = ctx.getLongTermMemory(); diff --git a/docs/content/docs/development/memory/sensory_and_short_term_memory.md b/docs/content/docs/development/memory/sensory_and_short_term_memory.md index 71068fa8f..7dc72ac21 100644 --- a/docs/content/docs/development/memory/sensory_and_short_term_memory.md +++ b/docs/content/docs/development/memory/sensory_and_short_term_memory.md @@ -95,7 +95,7 @@ Python memory values must be checkpoint-stable primitives, unlike the Java contr {{< tab "Python" >}} ```python -@action(InputEvent.EVENT_TYPE) +@action(EventType.InputEvent) def process_event(event: Event, ctx: RunnerContext) -> None: memory: MemoryObject = ctx.sensory_memory # or ctx.short_term_memory # store primitive @@ -120,7 +120,7 @@ def process_event(event: Event, ctx: RunnerContext) -> None: {{< tab "Java" >}} ```java -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) +@Action(EventType.InputEvent) public static void processEvent(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); MemoryObject memory = ctx.getSensoryMemory(); // ctx.getShortTermMemory(); @@ -228,7 +228,7 @@ def first_action(event: Event, ctx: RunnerContext): ctx.send_event(MyEvent(value=data_ref)) ... -@action(MyEvent.EVENT_TYPE) +@action("MyEvent") @staticmethod def second_action(event: Event, ctx: RunnerContext): my_event = MyEvent.from_event(event) @@ -242,7 +242,7 @@ def second_action(event: Event, ctx: RunnerContext): {{< tab "Java" >}} ```java -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) +@Action(EventType.InputEvent) public static void firstAction(Event event, RunnerContext ctx) throws Exception { ... MemoryObject sensoryMemory = ctx.getSensoryMemory(); @@ -252,7 +252,7 @@ public static void firstAction(Event event, RunnerContext ctx) throws Exception ... } -@Action(listenEventTypes = {MyEvent.EVENT_TYPE}) +@Action("MyEvent") public static void secondAction(Event event, RunnerContext ctx) throws Exception { MyEvent myEvent = MyEvent.fromEvent(event); ... diff --git a/docs/content/docs/development/prompts.md b/docs/content/docs/development/prompts.md index 6bf9e77bb..8c57b5b0e 100644 --- a/docs/content/docs/development/prompts.md +++ b/docs/content/docs/development/prompts.md @@ -243,7 +243,7 @@ class ReviewAnalysisAgent(Agent): extract_reasoning=True, ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event and send chat request for review analysis.""" @@ -308,7 +308,7 @@ public class ReviewAnalysisAgent extends Agent { } /** Process input event and send chat request for review analysis. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); String input = (String) inputEvent.getInput(); diff --git a/docs/content/docs/development/vector_stores.md b/docs/content/docs/development/vector_stores.md index a00b0e359..07d5eafa7 100644 --- a/docs/content/docs/development/vector_stores.md +++ b/docs/content/docs/development/vector_stores.md @@ -362,7 +362,7 @@ class MyAgent(Agent): collection="my_chroma_store" ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def search_documents(event: Event, ctx: RunnerContext) -> None: # Get the vector store from the runtime context @@ -416,7 +416,7 @@ public class MyAgent extends Agent { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void searchDocuments(Event event, RunnerContext ctx) { InputEvent inputEvent = InputEvent.fromEvent(event); // Option 1: Manual search via the vector store @@ -429,7 +429,7 @@ public class MyAgent extends Agent { ctx.sendEvent(new ContextRetrievalRequestEvent(queryText, "vectorStore")); } - @Action(listenEventTypes = {ContextRetrievalResponseEvent.EVENT_TYPE}) + @Action(EventType.ContextRetrievalResponseEvent) public static void onSearchResponse(Event event, RunnerContext ctx) { ContextRetrievalResponseEvent response = ContextRetrievalResponseEvent.fromEvent(event); List documents = response.getDocuments(); @@ -1049,7 +1049,7 @@ class MyAgent(Agent): dims=768 ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: # Use Java vector store from Python @@ -1096,7 +1096,7 @@ public class MyAgent extends Agent { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); // Use Python vector store from Java diff --git a/docs/content/docs/development/workflow_agent.md b/docs/content/docs/development/workflow_agent.md index b8b7e860d..4ac6584f4 100644 --- a/docs/content/docs/development/workflow_agent.md +++ b/docs/content/docs/development/workflow_agent.md @@ -26,7 +26,7 @@ under the License. A workflow style agent in Flink-Agents is an agent whose reasoning and behavior are organized as a directed workflow of modular steps, called actions, connected by events. This design is inspired by the need to orchestrate complex, multi-stage tasks in a transparent, extensible, and data-centric way, leveraging Apache Flink's streaming architecture. -In Flink-Agents, a workflow agent is defined as a class that inherits from the `Agent` base class. The agent's logic is expressed as a set of actions, each of which is a function decorated with `@action(EventType)` in python (or a method annotated with `@Action(listenEventTypes = {})` in java). Actions consume events, perform reasoning or tool calls, and emit new events, which may trigger downstream actions. This event-driven workflow forms a directed cyclic graph of computation, where each node is an action and each edge is an event type. +In Flink-Agents, a workflow agent is defined as a class that inherits from the `Agent` base class. The agent's logic is expressed as a set of actions, each of which is a function decorated with `@action(EventType.X)` in python (or a method annotated with `@Action(EventType.X)` in java). Actions consume events, perform reasoning or tool calls, and emit new events, which may trigger downstream actions. This event-driven workflow forms a directed cyclic graph of computation, where each node is an action and each edge is an event type. A workflow agent is well-suited for scenarios where the solution requires explicit orchestration, branching, or multi-step reasoning, such as data enrichment, multi-tool pipelines, or complex business logic. @@ -85,7 +85,7 @@ class ReviewAnalysisAgent(Agent): extract_reasoning=True, ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event and send chat request for review analysis.""" @@ -106,7 +106,7 @@ class ReviewAnalysisAgent(Agent): ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat response event and send output event.""" @@ -176,7 +176,7 @@ public class ReviewAnalysisAgent extends Agent { } /** Process input event and send chat request for review analysis. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); String input = (String) inputEvent.getInput(); @@ -197,7 +197,7 @@ public class ReviewAnalysisAgent extends Agent { "reviewAnalysisModel", List.of(msg), Map.of("input", content), null)); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(Event event, RunnerContext ctx) throws Exception { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); @@ -242,7 +242,7 @@ The decorated/annotated function signature should be `(Event, RunnerContext) -> {{< tab "Python" >}} ```python class ReviewAnalysisAgent(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: # the action logic @@ -253,7 +253,7 @@ class ReviewAnalysisAgent(Agent): ```java public class ReviewAnalysisAgent extends Agent { /** Process input event and send chat request for review analysis. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); // the action logic @@ -272,7 +272,7 @@ In the function, user can also send new events, to trigger other actions, or out {{< tab "Python" >}} ```python -@action(InputEvent.EVENT_TYPE) +@action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: # send a ChatRequestEvent to trigger the built-in chat-model action @@ -282,9 +282,10 @@ def process_input(event: Event, ctx: RunnerContext) -> None: {{< tab "Java" >}} ```java -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) -public static void processInput(Event event, RunnerContext ctx) { - // send a ChatRequestEvent to trigger the built-in chat-model action +@Action(EventType.InputEvent) +public static void processInput(Event event, RunnerContext ctx) throws Exception { + InputEvent inputEvent = InputEvent.fromEvent(event); + // send ChatRequestEvent ctx.sendEvent(new ChatRequestEvent("my_model", messages)); } ``` @@ -308,7 +309,7 @@ def emit_output(event: Event, ctx: RunnerContext) -> None: {{< tab "Java" >}} ```java -@Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) +@Action(EventType.ChatResponseEvent) public static void emitOutput(Event event, RunnerContext ctx) { // output data to downstream ctx.sendEvent(new OutputEvent(result)); @@ -359,7 +360,7 @@ Use a reconciler for durable calls when the original call may already have compl {{< tab "Python" >}} Python actions can call `ctx.durable_execute(...)` to run a synchronous durable code block. ```python -@action(InputEvent.EVENT_TYPE) +@action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: input_event = InputEvent.from_event(event) @@ -374,7 +375,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: You can also pass an optional `reconciler` callable to recover an execution outcome during recovery. ```python -@action(InputEvent.EVENT_TYPE) +@action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: input_event = InputEvent.from_event(event) @@ -400,7 +401,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: {{< tab "Java" >}} Java actions use `DurableCallable` with `ctx.durableExecute(...)`, where `getId()` must be stable and `getResultClass()` supports recovery deserialization. ```java -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) +@Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); DurableCallable call = new DurableCallable<>() { @@ -428,7 +429,7 @@ public static void processInput(Event event, RunnerContext ctx) throws Exception Java actions can also override `reconciler()` to recover an execution outcome during recovery. ```java -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) +@Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); DurableCallable call = new DurableCallable<>() { @@ -476,7 +477,7 @@ Async execution uses the same durable semantics but yields while waiting for a t {{< tab "Python" >}} Define an `async def` action and `await ctx.durable_execute_async(...)`. The same optional `reconciler=...` argument is available for recovery. ```python -@action(InputEvent.EVENT_TYPE) +@action(EventType.InputEvent) @staticmethod async def process_with_async(event: Event, ctx: RunnerContext) -> None: input_event = InputEvent.from_event(event) @@ -498,7 +499,7 @@ functions like `asyncio.gather`, `asyncio.wait`, `asyncio.create_task`, and Use `ctx.durableExecuteAsync(DurableCallable)`; on **JDK 21+** it yields using Continuation, and on **JDK < 21** it falls back to synchronous execution. The same optional `reconciler()` hook can be used for recovery. ```java -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) +@Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); DurableCallable call = new DurableCallable<>() { @@ -557,7 +558,7 @@ class MyAgent(Agent): ```java public class MyAgent extends Agent { @Action( - listenEventTypes = {InputEvent.EVENT_TYPE}, + value = EventType.InputEvent, target = @PythonFunction( module = "my_pkg.handlers", qualname = "handle_input")) @@ -595,7 +596,7 @@ For simple cases, users can pass data between actions directly using `Event` wit {{< tab "Python" >}} ```python # Send a unified event from one action -@action(InputEvent.EVENT_TYPE) +@action(EventType.InputEvent) @staticmethod def create_my_event(event: Event, ctx: RunnerContext) -> None: ctx.send_event( @@ -614,13 +615,13 @@ def handle_my_event(event: Event, ctx: RunnerContext) -> None: {{< tab "Java" >}} ```java // Send a unified event from one action -@Action(listenEventTypes = {InputEvent.EVENT_TYPE}) +@Action(EventType.InputEvent) public static void createMyEvent(Event event, RunnerContext ctx) { ctx.sendEvent(new Event("my_event", Map.of("field1", "test", "field2", 42))); } // Consume it in another action -@Action(listenEventTypes = {"my_event"}) +@Action("my_event") public static void handleMyEvent(Event event, RunnerContext ctx) { String field1 = (String) event.getAttr("field1"); int field2 = (int) event.getAttr("field2"); diff --git a/docs/content/docs/development/yaml.md b/docs/content/docs/development/yaml.md index be224f946..41e2f5ac2 100644 --- a/docs/content/docs/development/yaml.md +++ b/docs/content/docs/development/yaml.md @@ -60,11 +60,11 @@ agents: actions: - name: process_input function: my_pkg.actions:process_input - listen_to: [input] + trigger_conditions: [input] type: python - name: process_chat_response function: my_pkg.actions:process_chat_response - listen_to: [chat_response] + trigger_conditions: [chat_response] type: python # ---- Resources ---- @@ -225,7 +225,7 @@ Inline action (map) fields: |-------|----------|-------------| | `name` | yes | Action name (unique within the agent). | | `function` | yes | Fully-qualified callable in the form `:`. See [Function references](#function-references). | -| `listen_to` | yes | List of event types the action listens to. Built-in [event aliases](#event-aliases) (`input`, `chat_request`, ...) or your own event-type strings. | +| `trigger_conditions` | yes | List of event types the action listens to. Built-in [event aliases](#event-aliases) (`input`, `chat_request`, ...) or your own event-type strings. | | `type` | no | Implementation language: `python` or `java`. Defaults to `python` (see [Selecting the implementation language](#selecting-the-implementation-language)). | | `config` | no | Free-form configuration map passed to the action at runtime. | @@ -233,11 +233,11 @@ Inline action (map) fields: actions: - name: action1 function: my_pkg.actions:action1 - listen_to: [input] + trigger_conditions: [input] type: python - name: action2 function: my_pkg.actions:action2 - listen_to: [chat_response] + trigger_conditions: [chat_response] type: python - action3 # shared action reference (declared at file level) ``` @@ -302,7 +302,7 @@ agents: - action1 # shared action - name: my_action function: my_pkg.actions:my_action - listen_to: [input] + trigger_conditions: [input] - name: agent2 description: The second agent @@ -313,11 +313,11 @@ agents: actions: - name: action1 function: my_pkg.actions:action1 - listen_to: [input] + trigger_conditions: [input] type: python - name: action2 function: my_pkg.actions:action2 - listen_to: [chat_response] + trigger_conditions: [chat_response] type: python ``` @@ -445,7 +445,7 @@ When `type:` resolves to the **opposite** language of the loader, the loader bui ### Provider aliases -For `clazz:` on resource descriptors and for event names in `listen_to:`, you can use a short alias instead of a fully-qualified class path. +For `clazz:` on resource descriptors and for event names in `trigger_conditions:`, you can use a short alias instead of a fully-qualified class path. #### Event aliases @@ -512,10 +512,10 @@ agents: actions: - name: process_input function: my_pkg.actions:process_input - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response function: my_pkg.actions:process_chat_response - listen_to: [chat_response] + trigger_conditions: [chat_response] chat_model_connections: # Python Ollama connection used by the math chat model diff --git a/docs/content/docs/get-started/quickstart/parallel_llm.md b/docs/content/docs/get-started/quickstart/parallel_llm.md index 5a4b75c09..b42b61eb5 100644 --- a/docs/content/docs/get-started/quickstart/parallel_llm.md +++ b/docs/content/docs/get-started/quickstart/parallel_llm.md @@ -278,7 +278,7 @@ public class ParallelChatAgent extends Agent { } /** Process input event and dispatch a SentimentInputEvent for each aspect handler. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void requestAspectJudgments(Event event, RunnerContext ctx) throws Exception { CustomTypesAndResources.SentimentRequest request = (CustomTypesAndResources.SentimentRequest) InputEvent.fromEvent(event).getInput(); @@ -291,7 +291,7 @@ public class ParallelChatAgent extends Agent { } /** Handle taste aspect: build and send ChatRequestEvent for taste judgment. */ - @Action(listenEventTypes = {SENTIMENT_INPUT_EVENT_TYPE}) + @Action(SENTIMENT_INPUT_EVENT_TYPE) public static void handleTasteInput(Event event, RunnerContext ctx) throws Exception { ChatRequestEvent req = buildAspectRequest((String) event.getAttr("text"), "taste"); ctx.getSensoryMemory().set("aspect_map." + req.getId(), "taste"); @@ -299,14 +299,14 @@ public class ParallelChatAgent extends Agent { } /** Handle service aspect: build and send ChatRequestEvent for service judgment. */ - @Action(listenEventTypes = {SENTIMENT_INPUT_EVENT_TYPE}) + @Action(SENTIMENT_INPUT_EVENT_TYPE) public static void handleServiceInput(Event event, RunnerContext ctx) throws Exception { ChatRequestEvent req = buildAspectRequest((String) event.getAttr("text"), "service"); ctx.getSensoryMemory().set("aspect_map." + req.getId(), "service"); ctx.sendEvent(req); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void handleResponse(Event event, RunnerContext ctx) throws Exception { ... } diff --git a/docs/content/docs/get-started/quickstart/skills_agent.md b/docs/content/docs/get-started/quickstart/skills_agent.md index 9a15b3707..a95a276a9 100644 --- a/docs/content/docs/get-started/quickstart/skills_agent.md +++ b/docs/content/docs/get-started/quickstart/skills_agent.md @@ -107,7 +107,7 @@ class MathAgent(Agent): allowed_commands=["echo", "bc"], ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event and send a chat request to evaluate the question.""" @@ -119,7 +119,7 @@ class MathAgent(Agent): ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat response event and send the answer as output.""" @@ -167,7 +167,7 @@ public class MathAgent extends Agent { } /** Process input event and send a chat request to evaluate the question. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(InputEvent event, RunnerContext ctx) { ctx.sendEvent( new ChatRequestEvent( @@ -177,7 +177,7 @@ public class MathAgent extends Agent { } /** Process chat response event and send the answer as output. */ - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(ChatResponseEvent event, RunnerContext ctx) { ctx.sendEvent(new OutputEvent(event.getResponse().getContent())); } diff --git a/docs/content/docs/get-started/quickstart/workflow_agent.md b/docs/content/docs/get-started/quickstart/workflow_agent.md index 3fc3d81da..3e238475a 100644 --- a/docs/content/docs/get-started/quickstart/workflow_agent.md +++ b/docs/content/docs/get-started/quickstart/workflow_agent.md @@ -128,7 +128,7 @@ class ReviewAnalysisAgent(Agent): extract_reasoning=True, ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event and send chat request for review analysis.""" @@ -148,7 +148,7 @@ class ReviewAnalysisAgent(Agent): ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat response event and send output event.""" @@ -218,7 +218,7 @@ public class ReviewAnalysisAgent extends Agent { } /** Process input event and send chat request for review analysis. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); String input = (String) inputEvent.getInput(); @@ -239,7 +239,7 @@ public class ReviewAnalysisAgent extends Agent { "reviewAnalysisModel", List.of(msg), Map.of("input", content), null)); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(Event event, RunnerContext ctx) throws Exception { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); @@ -389,7 +389,7 @@ public class TableReviewAnalysisAgent extends Agent { // prompt / tool / chat model setup are identical to ReviewAnalysisAgent. - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) { // Table input arrives as a Row keyed by column name, not a POJO. Row row = (Row) InputEvent.fromEvent(event).getInput(); diff --git a/docs/content/docs/get-started/quickstart/yaml_agent.md b/docs/content/docs/get-started/quickstart/yaml_agent.md index e6b49b378..82fb55bcb 100644 --- a/docs/content/docs/get-started/quickstart/yaml_agent.md +++ b/docs/content/docs/get-started/quickstart/yaml_agent.md @@ -51,10 +51,10 @@ agents: actions: - name: process_input function: flink_agents.examples.quickstart.agents.review_analysis_agent:ReviewAnalysisAgent.process_input - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response function: flink_agents.examples.quickstart.agents.review_analysis_agent:ReviewAnalysisAgent.process_chat_response - listen_to: [chat_response] + trigger_conditions: [chat_response] chat_model_connections: - name: ollama_server @@ -120,11 +120,11 @@ agents: - name: processInput type: java function: org.apache.flink.agents.examples.agents.ReviewAnalysisAgent:processInput - listen_to: [input] + trigger_conditions: [input] - name: processChatResponse type: java function: org.apache.flink.agents.examples.agents.ReviewAnalysisAgent:processChatResponse - listen_to: [chat_response] + trigger_conditions: [chat_response] chat_model_connections: - name: ollama_server @@ -188,7 +188,7 @@ agents: A few things to notice in the YAML above: - `clazz: ollama` is an alias resolved by the loader to the full Ollama chat-model class — see the alias table in the [YAML API]({{< ref "docs/development/yaml#class-aliases" >}}) doc. -- `listen_to: [input]` / `[chat_response]` use **event aliases** for the framework's built-in events. +- `trigger_conditions: [input]` / `[chat_response]` use **event aliases** for the framework's built-in events. - `function:` strings use the `:` format. The right side is the class-qualified method name, so the YAML reuses the same `process_input` / `processInput` static methods the original `ReviewAnalysisAgent` already defines. - The prompt is declared inline as a `messages:` list and referenced from the chat-model setup by name. diff --git a/docs/content/docs/operations/monitoring.md b/docs/content/docs/operations/monitoring.md index eb6570237..021452125 100644 --- a/docs/content/docs/operations/monitoring.md +++ b/docs/content/docs/operations/monitoring.md @@ -62,7 +62,7 @@ Here is the user case example: {{< tab "Python" >}} ```python class MyAgent(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def first_action(event: Event, ctx: RunnerContext): start_time = time.time_ns() @@ -88,7 +88,7 @@ class MyAgent(Agent): ```java public class MyAgent extends Agent { - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void firstAction(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); long startTime = System.currentTimeMillis(); @@ -130,7 +130,7 @@ The Flink Agents' log system uses Flink's logging framework. For more details, p For adding logs in Java code, you can refer to [Flink documentation](https://nightlies.apache.org/flink/flink-docs-master/docs/deployment/advanced/logging/#best-practices-for-developers). In Python, you can add logs using `logging`. Here is a specific example: ```python -@action(InputEvent.EVENT_TYPE) +@action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: logging.info("Processing input event: %s", event) diff --git a/docs/yaml-schema.json b/docs/yaml-schema.json index 2b21d71db..39198c1c4 100644 --- a/docs/yaml-schema.json +++ b/docs/yaml-schema.json @@ -2,7 +2,7 @@ "$defs": { "ActionSpec": { "additionalProperties": false, - "description": "An action references a user function and the event types it listens to.\n\n``function`` is written as ``:`` \u2014 the\ncolon separates the Python module (or Java class FQN) from the\nattribute path inside it.\n\nAction signatures are fixed (``(Event, RunnerContext)``), so there is\nno ``parameter_types`` knob \u2014 Python doesn't need it, and the Java\naction signature is determined by the action contract.", + "description": "An action references a user function and its trigger conditions.\n\n``function`` is written as ``:`` \u2014 the\ncolon separates the Python module (or Java class FQN) from the\nattribute path inside it.\n\n``trigger_conditions`` carries one or more strings. Each is either an\nevent-type name (bare identifier) or a future condition-expression\nform \u2014 the runtime classifies the string when it loads the plan.\n\nAction signatures are fixed (``(Event, RunnerContext)``), so there is\nno ``parameter_types`` knob \u2014 Python doesn't need it, and the Java\naction signature is determined by the action contract.", "properties": { "config": { "anyOf": [ @@ -29,18 +29,18 @@ "default": null, "title": "Function" }, - "listen_to": { + "name": { + "title": "Name", + "type": "string" + }, + "trigger_conditions": { "items": { "type": "string" }, "minItems": 1, - "title": "Listen To", + "title": "Trigger Conditions", "type": "array" }, - "name": { - "title": "Name", - "type": "string" - }, "type": { "anyOf": [ { @@ -60,7 +60,7 @@ }, "required": [ "name", - "listen_to" + "trigger_conditions" ], "title": "ActionSpec", "type": "object" diff --git a/e2e-test/cross-language-agent-plan-snapshots/java/agent_plan_with_python_action.json b/e2e-test/cross-language-agent-plan-snapshots/java/agent_plan_with_python_action.json index fd662469f..8b6e28867 100644 --- a/e2e-test/cross-language-agent-plan-snapshots/java/agent_plan_with_python_action.json +++ b/e2e-test/cross-language-agent-plan-snapshots/java/agent_plan_with_python_action.json @@ -8,7 +8,7 @@ "method_name" : "processChatRequestOrToolResponse", "parameter_types" : [ "org.apache.flink.agents.api.Event", "org.apache.flink.agents.api.context.RunnerContext" ] }, - "listen_event_types" : [ "_chat_request_event", "_tool_response_event" ], + "trigger_conditions" : [ "_chat_request_event", "_tool_response_event" ], "config" : null }, "context_retrieval_action" : { @@ -19,7 +19,7 @@ "method_name" : "processContextRetrievalRequest", "parameter_types" : [ "org.apache.flink.agents.api.Event", "org.apache.flink.agents.api.context.RunnerContext" ] }, - "listen_event_types" : [ "_context_retrieval_request_event" ], + "trigger_conditions" : [ "_context_retrieval_request_event" ], "config" : null }, "handle" : { @@ -29,7 +29,7 @@ "module" : "flink_agents.plan.tests.test_agent_plan_cross_language", "qualname" : "_dummy_action" }, - "listen_event_types" : [ "_input_event" ], + "trigger_conditions" : [ "_input_event" ], "config" : null }, "tool_call_action" : { @@ -40,7 +40,7 @@ "method_name" : "processToolRequest", "parameter_types" : [ "org.apache.flink.agents.api.Event", "org.apache.flink.agents.api.context.RunnerContext" ] }, - "listen_event_types" : [ "_tool_request_event" ], + "trigger_conditions" : [ "_tool_request_event" ], "config" : null } }, diff --git a/e2e-test/cross-language-agent-plan-snapshots/python/agent_plan_with_java_action.json b/e2e-test/cross-language-agent-plan-snapshots/python/agent_plan_with_java_action.json index dda6405d1..19dee444a 100644 --- a/e2e-test/cross-language-agent-plan-snapshots/python/agent_plan_with_java_action.json +++ b/e2e-test/cross-language-agent-plan-snapshots/python/agent_plan_with_java_action.json @@ -11,7 +11,7 @@ "org.apache.flink.agents.api.context.RunnerContext" ] }, - "listen_event_types": [ + "trigger_conditions": [ "_input_event" ], "config": null @@ -23,7 +23,7 @@ "module": "flink_agents.plan.actions.chat_model_action", "qualname": "process_chat_request_or_tool_response" }, - "listen_event_types": [ + "trigger_conditions": [ "_chat_request_event", "_tool_response_event" ], @@ -36,7 +36,7 @@ "module": "flink_agents.plan.actions.tool_call_action", "qualname": "process_tool_request" }, - "listen_event_types": [ + "trigger_conditions": [ "_tool_request_event" ], "config": null @@ -48,7 +48,7 @@ "module": "flink_agents.plan.actions.context_retrieval_action", "qualname": "process_context_retrieval_request" }, - "listen_event_types": [ + "trigger_conditions": [ "_context_retrieval_request_event" ], "config": null diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/AsyncExecutionAgent.java b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/AsyncExecutionAgent.java index 6d7fbd26f..c8df332f5 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/AsyncExecutionAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/AsyncExecutionAgent.java @@ -18,6 +18,7 @@ package org.apache.flink.agents.integration.test; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -94,7 +95,7 @@ public String getProcessedResult() { */ public static class SimpleAsyncAgent extends Agent { - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); AsyncRequest request = (AsyncRequest) inputEvent.getInput(); @@ -135,7 +136,7 @@ public String call() { * @param event The processed event * @param ctx The runner context for sending events */ - @Action(listenEventTypes = {AsyncProcessedEvent.EVENT_TYPE}) + @Action(AsyncProcessedEvent.EVENT_TYPE) public static void generateOutput(Event event, RunnerContext ctx) throws Exception { AsyncProcessedEvent processedEvent = (AsyncProcessedEvent) event; @@ -153,7 +154,7 @@ public static void generateOutput(Event event, RunnerContext ctx) throws Excepti /** Agent that chains multiple durableExecuteAsync calls. */ public static class MultiAsyncAgent extends Agent { - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processWithMultipleAsync(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); @@ -261,7 +262,7 @@ public String getTimestampDir() { return timestampDir; } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processWithTiming(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); AsyncRequest request = (AsyncRequest) inputEvent.getInput(); @@ -303,7 +304,7 @@ public String call() { /** Agent that uses durableExecute (sync) for simulating slow operations. */ public static class SyncDurableAgent extends Agent { - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInputSync(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); AsyncRequest request = (AsyncRequest) inputEvent.getInput(); diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/ChatModelIntegrationAgent.java b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/ChatModelIntegrationAgent.java index 4492a8f48..ee64d1dff 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/ChatModelIntegrationAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/ChatModelIntegrationAgent.java @@ -19,6 +19,7 @@ package org.apache.flink.agents.integration.test; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -217,7 +218,7 @@ public static double createRandomNumber() { return Math.random(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void process(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); ctx.sendEvent( @@ -228,7 +229,7 @@ public static void process(Event event, RunnerContext ctx) throws Exception { MessageRole.USER, (String) inputEvent.getInput())))); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(Event event, RunnerContext ctx) { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); ctx.sendEvent(new OutputEvent(chatResponse.getResponse().getContent())); diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/EmbeddingIntegrationAgent.java b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/EmbeddingIntegrationAgent.java index 08fa3a1cc..2167d1332 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/EmbeddingIntegrationAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/EmbeddingIntegrationAgent.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -130,7 +131,7 @@ public static float validateSimilarityCalculation( } /** Main test action that processes input and validates embedding generation. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void testEmbeddingGeneration(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); String input = (String) inputEvent.getInput(); diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/FlinkIntegrationAgent.java b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/FlinkIntegrationAgent.java index 47cbd5924..bacb4aa0c 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/FlinkIntegrationAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/FlinkIntegrationAgent.java @@ -18,6 +18,7 @@ package org.apache.flink.agents.integration.test; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -89,7 +90,7 @@ public static class DataStreamAgent extends Agent { * @param event The input event to process * @param ctx The runner context for sending events */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); ItemData item = (ItemData) inputEvent.getInput(); @@ -114,7 +115,7 @@ public static void processInput(Event event, RunnerContext ctx) throws Exception * @param event The processed event * @param ctx The runner context for sending events */ - @Action(listenEventTypes = {ProcessedEvent.EVENT_TYPE}) + @Action(ProcessedEvent.EVENT_TYPE) public static void generateOutput(Event event, RunnerContext ctx) throws Exception { ProcessedEvent processedEvent = (ProcessedEvent) event; MemoryRef itemRef = processedEvent.getItemRef(); @@ -143,7 +144,7 @@ public static class TableAgent extends Agent { * @param event The input event to process * @param ctx The runner context for sending events */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); Object input = inputEvent.getInput(); @@ -168,7 +169,7 @@ public static void processInput(Event event, RunnerContext ctx) throws Exception * @param event The processed event * @param ctx The runner context for sending events */ - @Action(listenEventTypes = {ProcessedEvent.EVENT_TYPE}) + @Action(ProcessedEvent.EVENT_TYPE) public static void generateOutput(Event event, RunnerContext ctx) throws Exception { ProcessedEvent processedEvent = (ProcessedEvent) event; MemoryRef inputRef = processedEvent.getItemRef(); diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/MemoryObjectAgent.java b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/MemoryObjectAgent.java index d8ec4e7f0..094daf270 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/MemoryObjectAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/MemoryObjectAgent.java @@ -18,6 +18,7 @@ package org.apache.flink.agents.integration.test; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -76,7 +77,7 @@ public int hashCode() { } } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void testMemoryObject(Event event, RunnerContext ctx) throws Exception { MemoryObject stm = ctx.getShortTermMemory(); MemoryObject sm = ctx.getSensoryMemory(); diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/SkillsIntegrationAgent.java b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/SkillsIntegrationAgent.java index b35338242..858f58d1a 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/SkillsIntegrationAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/SkillsIntegrationAgent.java @@ -18,6 +18,7 @@ package org.apache.flink.agents.integration.test; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -103,7 +104,7 @@ public static org.apache.flink.agents.api.prompt.Prompt systemPrompt() { + "first and strictly follow the instructions of the skill."))); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void process(InputEvent event, RunnerContext ctx) throws Exception { ctx.sendEvent( new ChatRequestEvent( @@ -112,7 +113,7 @@ public static void process(InputEvent event, RunnerContext ctx) throws Exception new ChatMessage(MessageRole.USER, (String) event.getInput())))); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(ChatResponseEvent event, RunnerContext ctx) { ctx.sendEvent(new OutputEvent(event.getResponse().getContent())); } diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/TokenMetricsE2EAgent.java b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/TokenMetricsE2EAgent.java index 9cefc284c..22608a2c0 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/TokenMetricsE2EAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/TokenMetricsE2EAgent.java @@ -18,6 +18,7 @@ package org.apache.flink.agents.integration.test; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -60,7 +61,7 @@ public static ResourceDescriptor chatModel() { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void process(InputEvent event, RunnerContext ctx) throws Exception { ctx.sendEvent( new ChatRequestEvent( @@ -69,7 +70,7 @@ public static void process(InputEvent event, RunnerContext ctx) throws Exception new ChatMessage(MessageRole.USER, (String) event.getInput())))); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(ChatResponseEvent event, RunnerContext ctx) { ctx.sendEvent(new OutputEvent(event.getResponse().getContent())); } diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/VectorStoreIntegrationAgent.java b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/VectorStoreIntegrationAgent.java index 9740eddb3..ad48d5eac 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/VectorStoreIntegrationAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/java/org/apache/flink/agents/integration/test/VectorStoreIntegrationAgent.java @@ -19,6 +19,7 @@ package org.apache.flink.agents.integration.test; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -93,7 +94,7 @@ public static ResourceDescriptor vectorStore() { } } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void inputEvent(Event event, RunnerContext ctx) { InputEvent inputEvent = InputEvent.fromEvent(event); final String input = (String) inputEvent.getInput(); @@ -101,7 +102,7 @@ public static void inputEvent(Event event, RunnerContext ctx) { ctx.sendEvent(new ContextRetrievalRequestEvent(input, "vectorStore")); } - @Action(listenEventTypes = {ContextRetrievalResponseEvent.EVENT_TYPE}) + @Action(EventType.ContextRetrievalResponseEvent) public static void contextRetrievalResponseEvent(Event event, RunnerContext ctx) { ContextRetrievalResponseEvent responseEvent = ContextRetrievalResponseEvent.fromEvent(event); diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/resources/yaml/yaml_multi_agent.yaml b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/resources/yaml/yaml_multi_agent.yaml index 179df06a1..8eab4f507 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/resources/yaml/yaml_multi_agent.yaml +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/resources/yaml/yaml_multi_agent.yaml @@ -18,7 +18,7 @@ agents: - name: chat_request type: java function: org.apache.flink.agents.integration.test.yaml.YamlChatActions:chatRequest - listen_to: [input] + trigger_conditions: [input] - process_chat_response - name: commentator_agent @@ -36,7 +36,7 @@ agents: - name: commentary_request type: java function: org.apache.flink.agents.integration.test.yaml.YamlChatActions:commentaryRequest - listen_to: [input] + trigger_conditions: [input] - process_chat_response # File-level shared resources reused by every agent above. @@ -51,4 +51,4 @@ actions: - name: process_chat_response type: java function: org.apache.flink.agents.integration.test.yaml.YamlChatActions:processChatResponse - listen_to: [chat_response] + trigger_conditions: [chat_response] diff --git a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/resources/yaml/yaml_test_agent.yaml b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/resources/yaml/yaml_test_agent.yaml index 549c38551..29bd23430 100644 --- a/e2e-test/flink-agents-end-to-end-tests-integration/src/test/resources/yaml/yaml_test_agent.yaml +++ b/e2e-test/flink-agents-end-to-end-tests-integration/src/test/resources/yaml/yaml_test_agent.yaml @@ -34,8 +34,8 @@ agents: - name: process_input type: java function: org.apache.flink.agents.integration.test.yaml.YamlChatActions:processInput - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response type: java function: org.apache.flink.agents.integration.test.yaml.YamlChatActions:processChatResponse - listen_to: [chat_response] + trigger_conditions: [chat_response] diff --git a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/ChatModelCrossLanguageAgent.java b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/ChatModelCrossLanguageAgent.java index dec657042..a2d78ecfb 100644 --- a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/ChatModelCrossLanguageAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/ChatModelCrossLanguageAgent.java @@ -19,6 +19,7 @@ package org.apache.flink.agents.resource.test; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -148,7 +149,7 @@ public static double createRandomNumber() { return Math.random(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void process(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); String model; @@ -166,7 +167,7 @@ public static void process(Event event, RunnerContext ctx) throws Exception { MessageRole.USER, (String) inputEvent.getInput())))); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(Event event, RunnerContext ctx) { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); ctx.sendEvent(new OutputEvent(chatResponse.getResponse().getContent())); diff --git a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/EmbeddingCrossLanguageAgent.java b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/EmbeddingCrossLanguageAgent.java index 84ed246c1..be5f8d494 100644 --- a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/EmbeddingCrossLanguageAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/EmbeddingCrossLanguageAgent.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -68,7 +69,7 @@ public static ResourceDescriptor embeddingModel() { } /** Main test action that processes input and validates embedding generation. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void testEmbeddingGeneration(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); String input = (String) inputEvent.getInput(); diff --git a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/MCPCrossLanguageAgent.java b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/MCPCrossLanguageAgent.java index 03893eda9..30b921e8c 100644 --- a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/MCPCrossLanguageAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/MCPCrossLanguageAgent.java @@ -18,6 +18,7 @@ package org.apache.flink.agents.resource.test; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -47,7 +48,7 @@ public static ResourceDescriptor pythonMCPServer() { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void process(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); Map testResult = new HashMap<>(); diff --git a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/Mem0LongTermMemoryAgent.java b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/Mem0LongTermMemoryAgent.java index 9a7655b61..04e1970ae 100644 --- a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/Mem0LongTermMemoryAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/Mem0LongTermMemoryAgent.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -172,7 +173,7 @@ public static ResourceDescriptor milvusLtmStore() { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void addItems(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); ItemData input = (ItemData) inputEvent.getInput(); @@ -213,7 +214,7 @@ public Void call() throws Exception { } @SuppressWarnings("unchecked") - @Action(listenEventTypes = {MyEvent}) + @Action(MyEvent) public static void retrieveItems(Event event, RunnerContext ctx) throws Exception { Map record = (Map) event.getAttr("value"); record.put("timestamp_second_action", Instant.now().toString()); diff --git a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/VectorStoreCrossLanguageAgent.java b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/VectorStoreCrossLanguageAgent.java index cacf62444..5518978ab 100644 --- a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/VectorStoreCrossLanguageAgent.java +++ b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/java/org/apache/flink/agents/resource/test/VectorStoreCrossLanguageAgent.java @@ -19,6 +19,7 @@ package org.apache.flink.agents.resource.test; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -106,7 +107,7 @@ public static ResourceDescriptor vectorStore() { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void inputEvent(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); final String input = (String) inputEvent.getInput(); @@ -203,7 +204,7 @@ public static void inputEvent(Event event, RunnerContext ctx) throws Exception { ctx.sendEvent(new ContextRetrievalRequestEvent(input, "vectorStore")); } - @Action(listenEventTypes = {ContextRetrievalResponseEvent.EVENT_TYPE}) + @Action(EventType.ContextRetrievalResponseEvent) public static void contextRetrievalResponseEvent(Event event, RunnerContext ctx) { ContextRetrievalResponseEvent responseEvent = ContextRetrievalResponseEvent.fromEvent(event); diff --git a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/resources/yaml/yaml_cross_language_actions_in_python.yaml b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/resources/yaml/yaml_cross_language_actions_in_python.yaml index 615489807..72f9259a1 100644 --- a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/resources/yaml/yaml_cross_language_actions_in_python.yaml +++ b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/resources/yaml/yaml_cross_language_actions_in_python.yaml @@ -40,8 +40,8 @@ agents: - name: process_input type: python function: flink_agents.e2e_tests.e2e_tests_resource_cross_language.yaml_cross_language_actions:process_input - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response type: python function: flink_agents.e2e_tests.e2e_tests_resource_cross_language.yaml_cross_language_actions:process_chat_response - listen_to: [chat_response] + trigger_conditions: [chat_response] diff --git a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/resources/yaml/yaml_cross_language_agent.yaml b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/resources/yaml/yaml_cross_language_agent.yaml index 783989075..74adcd5e8 100644 --- a/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/resources/yaml/yaml_cross_language_agent.yaml +++ b/e2e-test/flink-agents-end-to-end-tests-resource-cross-language/src/test/resources/yaml/yaml_cross_language_agent.yaml @@ -49,8 +49,8 @@ agents: - name: process_input type: java function: org.apache.flink.agents.resource.test.YamlCrossLanguageActions:processInput - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response type: java function: org.apache.flink.agents.resource.test.YamlCrossLanguageActions:processChatResponse - listen_to: [chat_response] + trigger_conditions: [chat_response] diff --git a/examples/src/main/java/org/apache/flink/agents/examples/agents/MathAgent.java b/examples/src/main/java/org/apache/flink/agents/examples/agents/MathAgent.java index 1056f877b..ba1ece089 100644 --- a/examples/src/main/java/org/apache/flink/agents/examples/agents/MathAgent.java +++ b/examples/src/main/java/org/apache/flink/agents/examples/agents/MathAgent.java @@ -17,6 +17,7 @@ */ package org.apache.flink.agents.examples.agents; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -84,7 +85,7 @@ public static ResourceDescriptor mathModel() { } /** Process input event and send a chat request to evaluate the question. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(InputEvent event, RunnerContext ctx) { ctx.sendEvent( new ChatRequestEvent( @@ -94,7 +95,7 @@ public static void processInput(InputEvent event, RunnerContext ctx) { } /** Process chat response event and send the answer as output. */ - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(ChatResponseEvent event, RunnerContext ctx) { ctx.sendEvent(new OutputEvent(event.getResponse().getContent())); } diff --git a/examples/src/main/java/org/apache/flink/agents/examples/agents/ParallelChatAgent.java b/examples/src/main/java/org/apache/flink/agents/examples/agents/ParallelChatAgent.java index 24c85214d..c2984e44e 100644 --- a/examples/src/main/java/org/apache/flink/agents/examples/agents/ParallelChatAgent.java +++ b/examples/src/main/java/org/apache/flink/agents/examples/agents/ParallelChatAgent.java @@ -18,6 +18,7 @@ package org.apache.flink.agents.examples.agents; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -133,7 +134,7 @@ private static OutputEvent buildOutputEvent( } /** Process input event and dispatch a SentimentInputEvent for each aspect handler. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void requestAspectJudgments(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); CustomTypesAndResources.SentimentRequest request = @@ -147,7 +148,7 @@ public static void requestAspectJudgments(Event event, RunnerContext ctx) throws } /** Handle taste aspect: build and send ChatRequestEvent for taste judgment. */ - @Action(listenEventTypes = {SENTIMENT_INPUT_EVENT_TYPE}) + @Action(SENTIMENT_INPUT_EVENT_TYPE) public static void handleTasteInput(Event event, RunnerContext ctx) throws Exception { ChatRequestEvent req = buildAspectRequest((String) event.getAttr("text"), "taste"); ctx.getSensoryMemory().set("aspect_map." + req.getId(), "taste"); @@ -155,7 +156,7 @@ public static void handleTasteInput(Event event, RunnerContext ctx) throws Excep } /** Handle service aspect: build and send ChatRequestEvent for service judgment. */ - @Action(listenEventTypes = {SENTIMENT_INPUT_EVENT_TYPE}) + @Action(SENTIMENT_INPUT_EVENT_TYPE) public static void handleServiceInput(Event event, RunnerContext ctx) throws Exception { ChatRequestEvent req = buildAspectRequest((String) event.getAttr("text"), "service"); ctx.getSensoryMemory().set("aspect_map." + req.getId(), "service"); @@ -163,7 +164,7 @@ public static void handleServiceInput(Event event, RunnerContext ctx) throws Exc } /** Process chat response event. */ - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void handleResponse(Event event, RunnerContext ctx) throws Exception { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); Object parsed = chatResponse.getResponse().getExtraArgs().get(STRUCTURED_OUTPUT); diff --git a/examples/src/main/java/org/apache/flink/agents/examples/agents/ProductSuggestionAgent.java b/examples/src/main/java/org/apache/flink/agents/examples/agents/ProductSuggestionAgent.java index 2d1e12225..8d5d0b90f 100644 --- a/examples/src/main/java/org/apache/flink/agents/examples/agents/ProductSuggestionAgent.java +++ b/examples/src/main/java/org/apache/flink/agents/examples/agents/ProductSuggestionAgent.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -72,7 +73,7 @@ public static org.apache.flink.agents.api.prompt.Prompt productSuggestionPrompt( } /** Process input event. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); String input = (String) inputEvent.getInput(); @@ -95,7 +96,7 @@ public static void processInput(Event event, RunnerContext ctx) throws Exception } /** Process chat response event. */ - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(Event event, RunnerContext ctx) throws Exception { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); // Fail fast on a malformed LLM response: a parse error here propagates and fails the diff --git a/examples/src/main/java/org/apache/flink/agents/examples/agents/ReviewAnalysisAgent.java b/examples/src/main/java/org/apache/flink/agents/examples/agents/ReviewAnalysisAgent.java index 7fbfe752a..2862e0ae4 100644 --- a/examples/src/main/java/org/apache/flink/agents/examples/agents/ReviewAnalysisAgent.java +++ b/examples/src/main/java/org/apache/flink/agents/examples/agents/ReviewAnalysisAgent.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -87,7 +88,7 @@ public static void notifyShippingManager( } /** Process input event and send chat request for review analysis. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); String input = (String) inputEvent.getInput(); @@ -108,7 +109,7 @@ public static void processInput(Event event, RunnerContext ctx) throws Exception "reviewAnalysisModel", List.of(msg), Map.of("input", content), null)); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(Event event, RunnerContext ctx) throws Exception { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); // Fail fast on a malformed LLM response: a parse error here propagates and fails the diff --git a/examples/src/main/java/org/apache/flink/agents/examples/agents/TableReviewAnalysisAgent.java b/examples/src/main/java/org/apache/flink/agents/examples/agents/TableReviewAnalysisAgent.java index 18d754be2..a692b3e9b 100644 --- a/examples/src/main/java/org/apache/flink/agents/examples/agents/TableReviewAnalysisAgent.java +++ b/examples/src/main/java/org/apache/flink/agents/examples/agents/TableReviewAnalysisAgent.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -108,7 +109,7 @@ public static void notifyShippingManager( *

When using {@code fromTable()}, the input is a {@link Row} with fields matching the table * column names. */ - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void processInput(Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = InputEvent.fromEvent(event); Row row = (Row) inputEvent.getInput(); @@ -128,7 +129,7 @@ public static void processInput(Event event, RunnerContext ctx) throws Exception "reviewAnalysisModel", List.of(msg), Map.of("input", content), null)); } - @Action(listenEventTypes = {ChatResponseEvent.EVENT_TYPE}) + @Action(EventType.ChatResponseEvent) public static void processChatResponse(Event event, RunnerContext ctx) throws Exception { ChatResponseEvent chatResponse = ChatResponseEvent.fromEvent(event); // Fail fast on a malformed LLM response: a parse error here propagates and fails the diff --git a/examples/src/main/resources/yaml/yaml_review_analysis_agent.yaml b/examples/src/main/resources/yaml/yaml_review_analysis_agent.yaml index 723c1df98..689db6652 100644 --- a/examples/src/main/resources/yaml/yaml_review_analysis_agent.yaml +++ b/examples/src/main/resources/yaml/yaml_review_analysis_agent.yaml @@ -10,11 +10,11 @@ agents: - name: processInput type: java function: org.apache.flink.agents.examples.agents.ReviewAnalysisAgent:processInput - listen_to: [input] + trigger_conditions: [input] - name: processChatResponse type: java function: org.apache.flink.agents.examples.agents.ReviewAnalysisAgent:processChatResponse - listen_to: [chat_response] + trigger_conditions: [chat_response] chat_model_connections: - name: ollama_server diff --git a/plan/src/main/java/org/apache/flink/agents/plan/AgentPlan.java b/plan/src/main/java/org/apache/flink/agents/plan/AgentPlan.java index 1bd647764..8af6ca5f1 100644 --- a/plan/src/main/java/org/apache/flink/agents/plan/AgentPlan.java +++ b/plan/src/main/java/org/apache/flink/agents/plan/AgentPlan.java @@ -184,27 +184,27 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE private void extractActions( String actionName, - String[] listenEventTypeStrings, + String[] triggerEntries, org.apache.flink.agents.plan.Function function, Map config) throws Exception { - List eventTypeNames = new ArrayList<>(Arrays.asList(listenEventTypeStrings)); + List triggerConditions = new ArrayList<>(Arrays.asList(triggerEntries)); - if (eventTypeNames.isEmpty()) { + if (triggerConditions.isEmpty()) { throw new IllegalArgumentException( "Action " + actionName - + " must specify at least one event type via listenEventTypes."); + + " must specify at least one trigger entry via @Action(EventType.x)."); } // Create an Action - Action action = new Action(actionName, function, eventTypeNames, config); + Action action = new Action(actionName, function, triggerConditions, config); // Add to actions map actions.put(action.getName(), action); // Add to actionsByEvent map - for (String eventTypeName : eventTypeNames) { + for (String eventTypeName : triggerConditions) { actionsByEvent.computeIfAbsent(eventTypeName, k -> new ArrayList<>()).add(action); } } @@ -251,7 +251,7 @@ private void extractActionsFromAgent(Agent agent) throws Exception { Objects.requireNonNull( method.getAnnotation( org.apache.flink.agents.api.annotation.Action.class)); - String[] listenEventTypeStrings = actionAnnotation.listenEventTypes(); + String[] triggerEntries = actionAnnotation.value(); org.apache.flink.agents.api.annotation.PythonFunction target = actionAnnotation.target(); String targetModule = target.module(); @@ -276,7 +276,7 @@ private void extractActionsFromAgent(Agent agent) throws Exception { + method.getName() + "' must set both module and qualname"); } - extractActions(method.getName(), listenEventTypeStrings, execFunction, null); + extractActions(method.getName(), triggerEntries, execFunction, null); } for (Map.Entry< diff --git a/plan/src/main/java/org/apache/flink/agents/plan/actions/Action.java b/plan/src/main/java/org/apache/flink/agents/plan/actions/Action.java index 859795a69..18e3b83b4 100644 --- a/plan/src/main/java/org/apache/flink/agents/plan/actions/Action.java +++ b/plan/src/main/java/org/apache/flink/agents/plan/actions/Action.java @@ -33,17 +33,17 @@ import java.util.Objects; /** - * Representation of an agent action with event listening and function execution. + * Representation of an agent action with unified trigger conditions. * - *

This class encapsulates a named agent action that listens for specific event types and - * executes an associated function when those events occur. + *

Each entry of {@code triggerConditions} is an event type name string. Multiple entries combine + * with OR. */ @JsonSerialize(using = ActionJsonSerializer.class) @JsonDeserialize(using = ActionJsonDeserializer.class) public class Action { private final String name; private final Function exec; - private final List listenEventTypes; + private final List triggerConditions; // TODO: support nested map/list with non primitive type value. @Nullable private final Map config; @@ -51,18 +51,18 @@ public class Action { public Action( String name, Function exec, - List listenEventTypes, + List triggerConditions, @Nullable Map config) throws Exception { this.name = name; this.exec = exec; - this.listenEventTypes = listenEventTypes; + this.triggerConditions = triggerConditions; this.config = config; exec.checkSignature(new Class[] {Event.class, RunnerContext.class}); } - public Action(String name, Function exec, List listenEventTypes) throws Exception { - this(name, exec, listenEventTypes, null); + public Action(String name, Function exec, List triggerConditions) throws Exception { + this(name, exec, triggerConditions, null); } public String getName() { @@ -73,8 +73,19 @@ public Function getExec() { return exec; } + /** Returns the full trigger conditions list. */ + public List getTriggerConditions() { + return triggerConditions; + } + + /** + * Returns event-type names. Kept for callers that still consume the old naming; in this PR all + * trigger entries are plain event-type names so the list is identical to {@link + * #getTriggerConditions()}. A follow-up PR introduces CEL expressions and overrides this to + * filter out non-type entries. + */ public List getListenEventTypes() { - return listenEventTypes; + return triggerConditions; } @Nullable @@ -89,11 +100,11 @@ public boolean equals(Object o) { Action other = (Action) o; return name.equals(other.name) && exec.equals(other.exec) - && listenEventTypes.equals(other.listenEventTypes); + && Objects.equals(triggerConditions, other.triggerConditions); } @Override public int hashCode() { - return Objects.hash(name, exec, listenEventTypes); + return Objects.hash(name, exec, triggerConditions); } } diff --git a/plan/src/main/java/org/apache/flink/agents/plan/serializer/ActionJsonDeserializer.java b/plan/src/main/java/org/apache/flink/agents/plan/serializer/ActionJsonDeserializer.java index fec2f126f..efdda67fb 100644 --- a/plan/src/main/java/org/apache/flink/agents/plan/serializer/ActionJsonDeserializer.java +++ b/plan/src/main/java/org/apache/flink/agents/plan/serializer/ActionJsonDeserializer.java @@ -66,10 +66,10 @@ public Action deserialize(JsonParser jsonParser, DeserializationContext deserial throw new IOException("Unsupported function type: " + funcType); } - // Deserialize listenEventTypes - List listenEventTypes = new ArrayList<>(); - node.get("listen_event_types") - .forEach(eventTypeNode -> listenEventTypes.add(eventTypeNode.asText())); + // Deserialize trigger_conditions + List triggerConditions = new ArrayList<>(); + node.get("trigger_conditions") + .forEach(entryNode -> triggerConditions.add(entryNode.asText())); // Deserialize params Map config = null; @@ -88,7 +88,7 @@ public Action deserialize(JsonParser jsonParser, DeserializationContext deserial } try { - return new Action(name, func, listenEventTypes, config); + return new Action(name, func, triggerConditions, config); } catch (Exception e) { throw new RuntimeException( String.format("Failed to create Action with name \"%s\"", name), e); diff --git a/plan/src/main/java/org/apache/flink/agents/plan/serializer/ActionJsonSerializer.java b/plan/src/main/java/org/apache/flink/agents/plan/serializer/ActionJsonSerializer.java index 77581dadf..85e46823e 100644 --- a/plan/src/main/java/org/apache/flink/agents/plan/serializer/ActionJsonSerializer.java +++ b/plan/src/main/java/org/apache/flink/agents/plan/serializer/ActionJsonSerializer.java @@ -62,11 +62,11 @@ public void serialize( "Unsupported function type: " + action.getExec().getClass().getName()); } - // Write listenEventTypes field - jsonGenerator.writeFieldName("listen_event_types"); + // Write trigger_conditions field + jsonGenerator.writeFieldName("trigger_conditions"); jsonGenerator.writeStartArray(); - for (String eventType : action.getListenEventTypes()) { - jsonGenerator.writeString(eventType); + for (String entry : action.getTriggerConditions()) { + jsonGenerator.writeString(entry); } jsonGenerator.writeEndArray(); diff --git a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareChatModelTest.java b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareChatModelTest.java index 0ac51609e..561b2b5c6 100644 --- a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareChatModelTest.java +++ b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareChatModelTest.java @@ -22,7 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; -import org.apache.flink.agents.api.InputEvent; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.agents.Agent; import org.apache.flink.agents.api.annotation.Action; import org.apache.flink.agents.api.annotation.ChatModelSetup; @@ -85,7 +85,7 @@ public static ResourceDescriptor testChatModel() { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public void onInput(Event e, RunnerContext ctx) { // no-op for this test; validates action registration signature } diff --git a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareMCPServerTest.java b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareMCPServerTest.java index 719f195f5..70c8f7aa2 100644 --- a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareMCPServerTest.java +++ b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareMCPServerTest.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; -import org.apache.flink.agents.api.InputEvent; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.agents.Agent; import org.apache.flink.agents.api.annotation.Action; import org.apache.flink.agents.api.context.RunnerContext; @@ -80,7 +80,7 @@ public static ResourceDescriptor testMcpServer() { .build(); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public void process(Event event, RunnerContext ctx) { // no-op } diff --git a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareToolFieldTest.java b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareToolFieldTest.java index c87cc53f3..76f4f3ca5 100644 --- a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareToolFieldTest.java +++ b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareToolFieldTest.java @@ -21,7 +21,7 @@ package org.apache.flink.agents.plan; import org.apache.flink.agents.api.Event; -import org.apache.flink.agents.api.InputEvent; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.agents.Agent; import org.apache.flink.agents.api.annotation.Action; import org.apache.flink.agents.api.annotation.ToolParam; @@ -86,7 +86,7 @@ static class TestAgent extends Agent { @org.apache.flink.agents.api.annotation.Tool private final Tool weather = createWeatherTool(); - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public void onInput(Event e, RunnerContext ctx) { /* no-op */ } diff --git a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareToolMethodTest.java b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareToolMethodTest.java index a3784be59..a24cfbc76 100644 --- a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareToolMethodTest.java +++ b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanDeclareToolMethodTest.java @@ -22,7 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; -import org.apache.flink.agents.api.InputEvent; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.agents.Agent; import org.apache.flink.agents.api.annotation.Action; import org.apache.flink.agents.api.annotation.ToolParam; @@ -84,7 +84,7 @@ public static String getWeather( location, temp, "fahrenheit".equals(units) ? "F" : "C"); } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public void process(Event event, RunnerContext ctx) { // no-op } diff --git a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanTest.java b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanTest.java index acdf14343..230eb75f2 100644 --- a/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanTest.java +++ b/plan/src/test/java/org/apache/flink/agents/plan/AgentPlanTest.java @@ -19,6 +19,7 @@ package org.apache.flink.agents.plan; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -126,13 +127,15 @@ public Object getPythonResource() { /** Test agent class with annotated methods. */ public static class TestAgent extends Agent { - @org.apache.flink.agents.api.annotation.Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action(EventType.InputEvent) public void handleInputEvent(Event event, RunnerContext context) { InputEvent inputEvent = InputEvent.fromEvent(event); } - @org.apache.flink.agents.api.annotation.Action( - listenEventTypes = {TestEvent.EVENT_TYPE, OutputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action({ + TestEvent.EVENT_TYPE, + EventType.OutputEvent + }) public void handleMultipleEvents(Event event, RunnerContext context) { // Test action implementation } @@ -161,7 +164,7 @@ public static ResourceDescriptor pythonChatModel() { @Tool private TestTool anotherTool = new TestTool("anotherTool"); - @org.apache.flink.agents.api.annotation.Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action(EventType.InputEvent) public void handleInputEvent(Event event, RunnerContext context) { InputEvent inputEvent = InputEvent.fromEvent(event); } @@ -262,7 +265,7 @@ public void testBuiltInActionsAreJavaNativeAfterCompile() throws Exception { /** Cross-language action via {@code @Action(target = @PythonFunction(...))}. */ public static class AgentWithCrossLanguageAction extends Agent { @org.apache.flink.agents.api.annotation.Action( - listenEventTypes = {InputEvent.EVENT_TYPE}, + value = EventType.InputEvent, target = @org.apache.flink.agents.api.annotation.PythonFunction( module = "my_pkg.handlers", @@ -291,7 +294,7 @@ public void testActionWithPythonTargetCompilesToPythonFunctionExec() throws Exce /** Plain {@code @Action} (no {@code target}) compiles to a native Java exec. */ public static class AgentWithNativeJavaAction extends Agent { - @org.apache.flink.agents.api.annotation.Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action(EventType.InputEvent) public static void handle(Event event, RunnerContext ctx) { // intentionally empty } @@ -311,7 +314,7 @@ public void testActionWithEmptyTargetCompilesToJavaFunctionExec() throws Excepti /** Partially-set target (module without qualname) — must be rejected at compile. */ public static class AgentWithHalfSetPythonTargetMissingQualname extends Agent { @org.apache.flink.agents.api.annotation.Action( - listenEventTypes = {InputEvent.EVENT_TYPE}, + value = EventType.InputEvent, target = @org.apache.flink.agents.api.annotation.PythonFunction(module = "pkg")) public static void handle(Event event, RunnerContext ctx) { throw new UnsupportedOperationException("cross-language stub"); @@ -329,7 +332,7 @@ public void testActionWithPythonTargetMissingQualnameIsRejected() { /** Partially-set target (qualname without module) — must be rejected at compile. */ public static class AgentWithHalfSetPythonTargetMissingModule extends Agent { @org.apache.flink.agents.api.annotation.Action( - listenEventTypes = {InputEvent.EVENT_TYPE}, + value = EventType.InputEvent, target = @org.apache.flink.agents.api.annotation.PythonFunction( qualname = "handle_input")) @@ -350,7 +353,7 @@ public void testActionWithPythonTargetMissingModuleIsRejected() { * @Action declared on a parent agent class — must be rejected loudly, not silently dropped. */ public abstract static class BaseAgentWithInheritedAction extends Agent { - @org.apache.flink.agents.api.annotation.Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action(EventType.InputEvent) public static void sharedAction(Event event, RunnerContext ctx) { throw new UnsupportedOperationException("test stub"); } diff --git a/plan/src/test/java/org/apache/flink/agents/plan/compatibility/GenerateAgentPlanJson.java b/plan/src/test/java/org/apache/flink/agents/plan/compatibility/GenerateAgentPlanJson.java index 5051966ed..e657378d9 100644 --- a/plan/src/test/java/org/apache/flink/agents/plan/compatibility/GenerateAgentPlanJson.java +++ b/plan/src/test/java/org/apache/flink/agents/plan/compatibility/GenerateAgentPlanJson.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; -import org.apache.flink.agents.api.InputEvent; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.agents.Agent; import org.apache.flink.agents.api.annotation.Action; import org.apache.flink.agents.api.context.RunnerContext; @@ -48,12 +48,12 @@ public MyEvent() { /** Agent class for generating java agent plan json. */ public static class JavaAgentPlanCompatibilityTestAgent extends Agent { - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public void firstAction(Event event, RunnerContext context) { // Test action implementation } - @Action(listenEventTypes = {InputEvent.EVENT_TYPE, MyEvent.EVENT_TYPE}) + @Action({EventType.InputEvent, MyEvent.EVENT_TYPE}) public void secondAction(Event event, RunnerContext context) { // Test action implementation } diff --git a/plan/src/test/java/org/apache/flink/agents/plan/serializer/ActionJsonSerializerTest.java b/plan/src/test/java/org/apache/flink/agents/plan/serializer/ActionJsonSerializerTest.java index 6247b88c3..b6c2170b5 100644 --- a/plan/src/test/java/org/apache/flink/agents/plan/serializer/ActionJsonSerializerTest.java +++ b/plan/src/test/java/org/apache/flink/agents/plan/serializer/ActionJsonSerializerTest.java @@ -68,8 +68,8 @@ public void testSerializeJavaFunction() throws Exception { assertTrue( json.contains("\"method_name\":\"legal\""), "JSON should contain the method name"); assertTrue( - json.contains("\"listen_event_types\":["), - "JSON should contain the listen event types"); + json.contains("\"trigger_conditions\":["), + "JSON should contain the trigger conditions"); assertTrue( json.contains("\"" + InputEvent.EVENT_TYPE + "\""), "JSON should contain the event type string"); @@ -103,8 +103,8 @@ public void testSerializePythonFunction() throws Exception { json.contains("\"qualname\":\"test_function\""), "JSON should contain the qualified name"); assertTrue( - json.contains("\"listen_event_types\":["), - "JSON should contain the listen event types"); + json.contains("\"trigger_conditions\":["), + "JSON should contain the trigger conditions"); assertTrue( json.contains("\"" + InputEvent.EVENT_TYPE + "\""), "JSON should contain the event type string"); @@ -119,11 +119,11 @@ public void testSerializeMultipleEventTypes() throws Exception { "legal", new Class[] {Event.class, RunnerContext.class}); - // Create an Action with multiple event types - List eventTypes = new ArrayList<>(); - eventTypes.add(InputEvent.EVENT_TYPE); - eventTypes.add(OutputEvent.EVENT_TYPE); - Action action = new Action("multiEventAction", function, eventTypes); + // Create an Action with multiple trigger conditions + List triggerConditions = new ArrayList<>(); + triggerConditions.add(InputEvent.EVENT_TYPE); + triggerConditions.add(OutputEvent.EVENT_TYPE); + Action action = new Action("multiEventAction", function, triggerConditions); // Serialize the action to JSON String json = new ObjectMapper().writeValueAsString(action); @@ -133,8 +133,8 @@ public void testSerializeMultipleEventTypes() throws Exception { json.contains("\"name\":\"multiEventAction\""), "JSON should contain the action name"); assertTrue( - json.contains("\"listen_event_types\":["), - "JSON should contain the listen event types"); + json.contains("\"trigger_conditions\":["), + "JSON should contain the trigger conditions"); assertTrue( json.contains("\"" + InputEvent.EVENT_TYPE + "\""), "JSON should contain the InputEvent type string"); @@ -166,8 +166,8 @@ public void testSerializeEmptyEventTypes() throws Exception { json.contains("\"name\":\"emptyEventsAction\""), "JSON should contain the action name"); assertTrue( - json.contains("\"listen_event_types\":[]"), - "JSON should contain an empty listen event types array"); + json.contains("\"trigger_conditions\":[]"), + "JSON should contain an empty trigger conditions array"); } @Test diff --git a/plan/src/test/java/org/apache/flink/agents/plan/serializer/AgentPlanJsonSerializerTest.java b/plan/src/test/java/org/apache/flink/agents/plan/serializer/AgentPlanJsonSerializerTest.java index 2b9a91484..c8ba012b1 100644 --- a/plan/src/test/java/org/apache/flink/agents/plan/serializer/AgentPlanJsonSerializerTest.java +++ b/plan/src/test/java/org/apache/flink/agents/plan/serializer/AgentPlanJsonSerializerTest.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -42,18 +43,20 @@ public class AgentPlanJsonSerializerTest { /** Test Agent class with @Action annotated methods. */ public static class TestAgent extends Agent { - @org.apache.flink.agents.api.annotation.Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action(EventType.InputEvent) public void handleInputEvent(Event event, RunnerContext context) { InputEvent inputEvent = InputEvent.fromEvent(event); } - @org.apache.flink.agents.api.annotation.Action(listenEventTypes = {OutputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action(EventType.OutputEvent) public void processOutputEvent(Event event, RunnerContext context) { OutputEvent outputEvent = OutputEvent.fromEvent(event); } - @org.apache.flink.agents.api.annotation.Action( - listenEventTypes = {InputEvent.EVENT_TYPE, OutputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action({ + EventType.InputEvent, + EventType.OutputEvent + }) public void handleMultipleEvents(Event event, RunnerContext context) { // Test action logic for multiple event types } @@ -94,7 +97,7 @@ public void testSerializeAgentPlanWithActions() throws Exception { assertThat(json).contains("\"func_type\":\"JavaFunction\""); assertThat(json).contains("\"qualname\":\"org.apache.flink.agents.plan.TestAction\""); assertThat(json).contains("\"method_name\":\"legal\""); - assertThat(json).contains("\"listen_event_types\":["); + assertThat(json).contains("\"trigger_conditions\":["); assertThat(json).contains("\"" + InputEvent.EVENT_TYPE + "\""); assertThat(json).contains("\"actions_by_event\":{}"); } diff --git a/plan/src/test/resources/actions/action_invalid_event_type.json b/plan/src/test/resources/actions/action_invalid_event_type.json index 09a204144..b84d5c508 100644 --- a/plan/src/test/resources/actions/action_invalid_event_type.json +++ b/plan/src/test/resources/actions/action_invalid_event_type.json @@ -6,5 +6,5 @@ "method_name": "legal", "parameter_types": ["org.apache.flink.agents.api.Event"] }, - "listenEventTypes": ["org.apache.flink.agents.api.NonExistentEvent"] + "trigger_conditions": ["org.apache.flink.agents.api.NonExistentEvent"] } \ No newline at end of file diff --git a/plan/src/test/resources/actions/action_invalid_function_type.json b/plan/src/test/resources/actions/action_invalid_function_type.json index b2cec1f13..846c76267 100644 --- a/plan/src/test/resources/actions/action_invalid_function_type.json +++ b/plan/src/test/resources/actions/action_invalid_function_type.json @@ -6,5 +6,5 @@ "method_name": "legal", "parameter_types": ["org.apache.flink.agents.api.Event"] }, - "listenEventTypes": ["org.apache.flink.agents.api.InputEvent"] + "trigger_conditions": ["org.apache.flink.agents.api.InputEvent"] } \ No newline at end of file diff --git a/plan/src/test/resources/actions/action_java_function.json b/plan/src/test/resources/actions/action_java_function.json index 35fcbeedd..6b73f324a 100644 --- a/plan/src/test/resources/actions/action_java_function.json +++ b/plan/src/test/resources/actions/action_java_function.json @@ -6,5 +6,5 @@ "method_name": "legal", "parameter_types": ["org.apache.flink.agents.api.Event", "org.apache.flink.agents.api.context.RunnerContext"] }, - "listen_event_types": ["_input_event"] + "trigger_conditions": ["_input_event"] } diff --git a/plan/src/test/resources/actions/action_missing_fields.json b/plan/src/test/resources/actions/action_missing_fields.json index e2f261918..7e9bb0bc0 100644 --- a/plan/src/test/resources/actions/action_missing_fields.json +++ b/plan/src/test/resources/actions/action_missing_fields.json @@ -3,5 +3,5 @@ "exec": { "func_type": "JavaFunction" }, - "listenEventTypes": ["org.apache.flink.agents.api.InputEvent"] + "trigger_conditions": ["org.apache.flink.agents.api.InputEvent"] } \ No newline at end of file diff --git a/plan/src/test/resources/actions/action_python_function.json b/plan/src/test/resources/actions/action_python_function.json index 70fdf3aca..5711b873d 100644 --- a/plan/src/test/resources/actions/action_python_function.json +++ b/plan/src/test/resources/actions/action_python_function.json @@ -5,5 +5,5 @@ "module": "test_module", "qualname": "test_function" }, - "listen_event_types": ["_input_event"] + "trigger_conditions": ["_input_event"] } diff --git a/plan/src/test/resources/agent_plans/agent_plan.json b/plan/src/test/resources/agent_plans/agent_plan.json index 3cb8dcb25..52a1b5ad8 100644 --- a/plan/src/test/resources/agent_plans/agent_plan.json +++ b/plan/src/test/resources/agent_plans/agent_plan.json @@ -8,7 +8,7 @@ "parameter_types": ["org.apache.flink.agents.api.Event", "org.apache.flink.agents.api.context.RunnerContext"], "func_type": "JavaFunction" }, - "listen_event_types": [ + "trigger_conditions": [ "_input_event" ] }, @@ -20,7 +20,7 @@ "parameter_types": ["org.apache.flink.agents.api.Event", "org.apache.flink.agents.api.context.RunnerContext"], "func_type": "JavaFunction" }, - "listen_event_types": [ + "trigger_conditions": [ "_input_event", "MyEvent" ] diff --git a/plan/src/test/resources/agent_plans/agent_plan_with_python_resource_providers.json b/plan/src/test/resources/agent_plans/agent_plan_with_python_resource_providers.json index cb7e9170d..abd08e2d3 100644 --- a/plan/src/test/resources/agent_plans/agent_plan_with_python_resource_providers.json +++ b/plan/src/test/resources/agent_plans/agent_plan_with_python_resource_providers.json @@ -7,7 +7,7 @@ "module": "flink_agents.plan.tests.compatibility.python_agent_plan_compatibility_test_agent", "qualname": "PythonAgentPlanCompatibilityTestAgent.first_action" }, - "listen_event_types": [ + "trigger_conditions": [ "_input_event" ] }, @@ -18,7 +18,7 @@ "module": "flink_agents.plan.tests.compatibility.python_agent_plan_compatibility_test_agent", "qualname": "PythonAgentPlanCompatibilityTestAgent.second_action" }, - "listen_event_types": [ + "trigger_conditions": [ "_input_event", "_my_event" ] @@ -30,7 +30,7 @@ "module": "flink_agents.plan.actions.chat_model_action", "qualname": "process_chat_request_or_tool_response" }, - "listen_event_types": [ + "trigger_conditions": [ "_chat_request_event", "_tool_response_event" ] @@ -42,7 +42,7 @@ "module": "flink_agents.plan.actions.tool_call_action", "qualname": "process_tool_request" }, - "listen_event_types": [ + "trigger_conditions": [ "_tool_request_event" ] } diff --git a/python/flink_agents/api/agents/agent.py b/python/flink_agents/api/agents/agent.py index 3a6aed852..4e7dba086 100644 --- a/python/flink_agents/api/agents/agent.py +++ b/python/flink_agents/api/agents/agent.py @@ -39,7 +39,7 @@ class Agent(ABC): :: class MyAgent(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def my_action(event: Event, ctx: RunnerContext) -> None: action logic @@ -62,7 +62,7 @@ def my_chat_model() -> ResourceDescriptor: my_agent = Agent() my_agent.add_action(name="my_action", - events=["_input_event"], + trigger_conditions=["_input_event"], func=action_function) .add_resource(name="my_connection", instance=ResourceDescriptor( @@ -112,7 +112,7 @@ def resources(self) -> Dict[ResourceType, Dict[str, Any]]: def add_action( self, name: str, - events: List[str], + trigger_conditions: List[str], func: Callable | Function, **config: Any, ) -> "Agent": @@ -122,8 +122,9 @@ def add_action( ---------- name : str The name of the action, should be unique in the same Agent. - events : list[str] - Type-identifier strings listened by this action. + trigger_conditions : list[str] + Trigger condition strings — each is either an event-type name + or a future condition-expression form (see ``@action``). func : Callable | Function Either a raw Python callable (it will be wrapped as a ``PythonFunction``) or a pre-built flink-agents ``Function`` @@ -141,7 +142,7 @@ def add_action( raise ValueError(msg) if not isinstance(func, Function): func = PythonFunction.from_callable(func) - self._actions[name] = (events, func, config if config else None) + self._actions[name] = (trigger_conditions, func, config if config else None) return self def add_resource( diff --git a/python/flink_agents/api/agents/react_agent.py b/python/flink_agents/api/agents/react_agent.py index c898d119b..c9b310ec7 100644 --- a/python/flink_agents/api/agents/react_agent.py +++ b/python/flink_agents/api/agents/react_agent.py @@ -33,6 +33,7 @@ from flink_agents.api.decorators import action from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ResourceDescriptor, ResourceType from flink_agents.api.runner_context import RunnerContext @@ -141,7 +142,7 @@ def __init__( self.add_action( name="start_action", - events=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], func=self.start_action, output_schema=OutputSchema(output_schema=output_schema) if output_schema else None, ) @@ -205,7 +206,7 @@ def start_action(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def stop_action(event: Event, ctx: RunnerContext) -> None: """Stop action to output result.""" diff --git a/python/flink_agents/api/decorators.py b/python/flink_agents/api/decorators.py index 6025ac393..5c3fd47dc 100644 --- a/python/flink_agents/api/decorators.py +++ b/python/flink_agents/api/decorators.py @@ -33,17 +33,19 @@ def _validate_target(target: Function, owner: str) -> None: def action( - *listen_events: str, + *trigger_conditions: str, target: Function | None = None, ) -> Callable: """Decorator for marking a function as an agent action. - Each argument is a type-identifier string that this action responds to. + Each argument is an event-type name string that this action responds to. + Multiple entries combine with OR semantics — the action triggers if any + one matches. Parameters ---------- - listen_events : str - Type-identifier strings that this action responds to. + trigger_conditions : str + Event-type name strings that this action responds to. target : Function, optional Cross-language function descriptor dispatched instead of the decorated body. The body becomes a stub — raise @@ -52,22 +54,25 @@ def action( Returns: ------- Callable - Decorator function that marks the target function with event listeners. + Decorator function that marks the target function with trigger conditions. Raises: ------ AssertionError - If no events are provided or if an argument is not a string. + If no conditions are given or any entry is not a non-empty string. TypeError If ``target`` is provided but is not a :class:`Function` descriptor. """ - assert len(listen_events) > 0, ( - "action must have at least one event type to listen to" + assert len(trigger_conditions) > 0, ( + "action must have at least one trigger condition (event-type name)" ) - for evt in listen_events: - assert isinstance(evt, str), ( - f"action must listen to string type identifiers, got {evt!r}" + for entry in trigger_conditions: + assert isinstance(entry, str), ( + f"action trigger condition must be a string, got {entry!r}" + ) + assert entry != "", ( + f"action trigger condition must be non-empty, got {entry!r}" ) if target is not None and not isinstance(target, Function): @@ -81,7 +86,7 @@ def decorator(func: Callable) -> Callable: if target is not None: _validate_target(target, func.__qualname__) func._target = target - func._listen_events = listen_events + func._trigger_conditions = trigger_conditions return func return decorator diff --git a/python/flink_agents/api/events/event_type.py b/python/flink_agents/api/events/event_type.py new file mode 100644 index 000000000..344d6167c --- /dev/null +++ b/python/flink_agents/api/events/event_type.py @@ -0,0 +1,61 @@ +################################################################################ +# 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. +################################################################################# +"""Built-in event-type constants, sourced from each ``XxxEvent.EVENT_TYPE``.""" + +from __future__ import annotations + +from flink_agents.api.events.chat_event import ( + ChatRequestEvent as _ChatRequestEvent, +) +from flink_agents.api.events.chat_event import ( + ChatResponseEvent as _ChatResponseEvent, +) +from flink_agents.api.events.context_retrieval_event import ( + ContextRetrievalRequestEvent as _ContextRetrievalRequestEvent, +) +from flink_agents.api.events.context_retrieval_event import ( + ContextRetrievalResponseEvent as _ContextRetrievalResponseEvent, +) +from flink_agents.api.events.event import ( + InputEvent as _InputEvent, +) +from flink_agents.api.events.event import ( + OutputEvent as _OutputEvent, +) +from flink_agents.api.events.tool_event import ( + ToolRequestEvent as _ToolRequestEvent, +) +from flink_agents.api.events.tool_event import ( + ToolResponseEvent as _ToolResponseEvent, +) + + +class EventType: + """Namespace of built-in event-type constants. + + Usage: ``@action(EventType.InputEvent)``. + """ + + InputEvent: str = _InputEvent.EVENT_TYPE + OutputEvent: str = _OutputEvent.EVENT_TYPE + ChatRequestEvent: str = _ChatRequestEvent.EVENT_TYPE + ChatResponseEvent: str = _ChatResponseEvent.EVENT_TYPE + ToolRequestEvent: str = _ToolRequestEvent.EVENT_TYPE + ToolResponseEvent: str = _ToolResponseEvent.EVENT_TYPE + ContextRetrievalRequestEvent: str = _ContextRetrievalRequestEvent.EVENT_TYPE + ContextRetrievalResponseEvent: str = _ContextRetrievalResponseEvent.EVENT_TYPE diff --git a/python/flink_agents/api/tests/test_agent_add_action.py b/python/flink_agents/api/tests/test_agent_add_action.py index ee7e59f2b..c11c04462 100644 --- a/python/flink_agents/api/tests/test_agent_add_action.py +++ b/python/flink_agents/api/tests/test_agent_add_action.py @@ -50,10 +50,10 @@ def test_add_action_accepts_python_function_descriptor_and_stores_as_is() -> Non agent = Agent() pf = PythonFunction(module="pkg.mod", qualname="MyClass.method") - agent.add_action(name="act", events=[InputEvent.EVENT_TYPE], func=pf) + agent.add_action(name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=pf) - events, stored, config = agent.actions["act"] - assert events == [InputEvent.EVENT_TYPE] + trigger_conditions, stored, config = agent.actions["act"] + assert trigger_conditions == [InputEvent.EVENT_TYPE] assert stored is pf, "PythonFunction descriptor should not be re-wrapped." assert config is None @@ -63,10 +63,10 @@ def test_add_action_accepts_java_function_descriptor_and_stores_as_is() -> None: agent = Agent() jf = _make_java_function() - agent.add_action(name="act", events=[InputEvent.EVENT_TYPE], func=jf) + agent.add_action(name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=jf) - events, stored, _ = agent.actions["act"] - assert events == [InputEvent.EVENT_TYPE] + trigger_conditions, stored, _ = agent.actions["act"] + assert trigger_conditions == [InputEvent.EVENT_TYPE] assert stored is jf, "JavaFunction descriptor should be stored as-is." assert isinstance(stored, JavaFunction) @@ -77,7 +77,7 @@ def test_add_action_accepts_java_function_descriptor_and_stores_as_is() -> None: def test_add_action_wraps_raw_callable_as_python_function() -> None: """Bare callables get auto-wrapped into a PythonFunction descriptor.""" agent = Agent() - agent.add_action(name="act", events=[InputEvent.EVENT_TYPE], func=_dummy_action) + agent.add_action(name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=_dummy_action) _, stored, _ = agent.actions["act"] assert isinstance(stored, PythonFunction) @@ -90,10 +90,10 @@ def test_add_action_wraps_raw_callable_as_python_function() -> None: def test_add_action_duplicate_name_rejected_python_function() -> None: agent = Agent() - agent.add_action(name="act", events=[InputEvent.EVENT_TYPE], func=_dummy_action) + agent.add_action(name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=_dummy_action) with pytest.raises(ValueError, match="act"): agent.add_action( - name="act", events=[InputEvent.EVENT_TYPE], func=_dummy_action + name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=_dummy_action ) @@ -101,11 +101,11 @@ def test_add_action_duplicate_name_rejected_java_function() -> None: """Duplicate-name rejection applies uniformly regardless of descriptor type.""" agent = Agent() agent.add_action( - name="act", events=[InputEvent.EVENT_TYPE], func=_make_java_function() + name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=_make_java_function() ) with pytest.raises(ValueError, match="act"): agent.add_action( - name="act", events=[InputEvent.EVENT_TYPE], func=_make_java_function() + name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=_make_java_function() ) @@ -116,7 +116,7 @@ def test_add_action_captures_config_kwargs() -> None: agent = Agent() agent.add_action( name="act", - events=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], func=_dummy_action, retry=3, timeout_sec=10, @@ -128,7 +128,7 @@ def test_add_action_captures_config_kwargs() -> None: def test_add_action_config_is_none_when_no_kwargs() -> None: agent = Agent() - agent.add_action(name="act", events=[InputEvent.EVENT_TYPE], func=_dummy_action) + agent.add_action(name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=_dummy_action) _, _, config = agent.actions["act"] assert config is None @@ -137,21 +137,21 @@ def test_add_action_config_is_none_when_no_kwargs() -> None: def test_add_action_returns_self_for_chaining() -> None: agent = Agent() result = agent.add_action( - name="act", events=[InputEvent.EVENT_TYPE], func=_dummy_action + name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=_dummy_action ) assert result is agent -# ── Multi-event subscription ──────────────────────────────────────────── +# ── Multiple trigger conditions ───────────────────────────────────────── -def test_add_action_supports_multiple_event_subscriptions() -> None: +def test_add_action_supports_multiple_trigger_conditions() -> None: agent = Agent() agent.add_action( name="multi", - events=["evt_a", "evt_b", "evt_c"], + trigger_conditions=["evt_a", "evt_b", "evt_c"], func=_make_java_function(), ) - events, _, _ = agent.actions["multi"] - assert events == ["evt_a", "evt_b", "evt_c"] + trigger_conditions, _, _ = agent.actions["multi"] + assert trigger_conditions == ["evt_a", "evt_b", "evt_c"] diff --git a/python/flink_agents/api/tests/test_decorators.py b/python/flink_agents/api/tests/test_decorators.py index 94ff8d86f..ccd58241b 100644 --- a/python/flink_agents/api/tests/test_decorators.py +++ b/python/flink_agents/api/tests/test_decorators.py @@ -19,29 +19,30 @@ from flink_agents.api.decorators import action from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.function import JavaFunction, PythonFunction from flink_agents.api.runner_context import RunnerContext def test_action_decorator() -> None: - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) def forward_action(event: Event, ctx: RunnerContext) -> None: input = InputEvent.from_event(event).input ctx.send_event(OutputEvent(output=input)) - assert hasattr(forward_action, "_listen_events") - listen_events = forward_action._listen_events + assert hasattr(forward_action, "_trigger_conditions") + listen_events = forward_action._trigger_conditions assert listen_events == (InputEvent.EVENT_TYPE,) def test_action_decorator_listen_multi_events() -> None: - @action(InputEvent.EVENT_TYPE, OutputEvent.EVENT_TYPE) + @action(EventType.InputEvent, EventType.OutputEvent) def forward_action(event: Event, ctx: RunnerContext) -> None: input = InputEvent.from_event(event).input ctx.send_event(OutputEvent(output=input)) - assert hasattr(forward_action, "_listen_events") - listen_events = forward_action._listen_events + assert hasattr(forward_action, "_trigger_conditions") + listen_events = forward_action._trigger_conditions assert listen_events == (InputEvent.EVENT_TYPE, OutputEvent.EVENT_TYPE) @@ -70,8 +71,8 @@ def test_action_decorator_with_string_identifier() -> None: def my_handler(event: Event, ctx: RunnerContext) -> None: pass - assert hasattr(my_handler, "_listen_events") - assert my_handler._listen_events == ("MyCustomEvent",) + assert hasattr(my_handler, "_trigger_conditions") + assert my_handler._trigger_conditions == ("MyCustomEvent",) def test_action_decorator_multiple_strings() -> None: @@ -81,7 +82,7 @@ def test_action_decorator_multiple_strings() -> None: def mixed_handler(event: Event, ctx: RunnerContext) -> None: pass - assert mixed_handler._listen_events == ("_input_event", "AnotherEvent") + assert mixed_handler._trigger_conditions == ("_input_event", "AnotherEvent") def test_action_decorator_rejects_invalid_types() -> None: @@ -100,25 +101,25 @@ def _java_target() -> JavaFunction: def test_action_decorator_with_cross_language_target() -> None: target = _java_target() - @action(InputEvent.EVENT_TYPE, target=target) + @action(EventType.InputEvent, target=target) def stub(event: Event, ctx: RunnerContext) -> None: msg = "cross-language stub" raise NotImplementedError(msg) - assert stub._listen_events == (InputEvent.EVENT_TYPE,) + assert stub._trigger_conditions == (InputEvent.EVENT_TYPE,) assert stub._target is target def test_action_decorator_rejects_non_function_target() -> None: with pytest.raises(TypeError, match="api-layer Function descriptor"): - @action(InputEvent.EVENT_TYPE, target="not a function") # type: ignore[arg-type] + @action(EventType.InputEvent, target="not a function") # type: ignore[arg-type] def stub(event: Event, ctx: RunnerContext) -> None: pass def test_action_decorator_without_target_does_not_set_attribute() -> None: - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) def regular(event: Event, ctx: RunnerContext) -> None: pass @@ -129,7 +130,7 @@ def test_action_decorator_rejects_java_target_with_empty_qualname() -> None: bad = JavaFunction(qualname="", method_name="handle", parameter_types=[]) with pytest.raises(ValueError, match="qualname"): - @action(InputEvent.EVENT_TYPE, target=bad) + @action(EventType.InputEvent, target=bad) def stub(event: Event, ctx: RunnerContext) -> None: pass @@ -138,7 +139,7 @@ def test_action_decorator_rejects_java_target_with_empty_method_name() -> None: bad = JavaFunction(qualname="com.example.X", method_name="", parameter_types=[]) with pytest.raises(ValueError, match="method_name"): - @action(InputEvent.EVENT_TYPE, target=bad) + @action(EventType.InputEvent, target=bad) def stub(event: Event, ctx: RunnerContext) -> None: pass @@ -147,7 +148,7 @@ def test_action_decorator_rejects_python_target_with_empty_module() -> None: bad = PythonFunction(module="", qualname="handle") with pytest.raises(ValueError, match="module"): - @action(InputEvent.EVENT_TYPE, target=bad) + @action(EventType.InputEvent, target=bad) def stub(event: Event, ctx: RunnerContext) -> None: pass @@ -156,7 +157,7 @@ def test_action_decorator_rejects_python_target_with_empty_qualname() -> None: bad = PythonFunction(module="pkg.mod", qualname="") with pytest.raises(ValueError, match="qualname"): - @action(InputEvent.EVENT_TYPE, target=bad) + @action(EventType.InputEvent, target=bad) def stub(event: Event, ctx: RunnerContext) -> None: pass @@ -165,6 +166,6 @@ def test_action_decorator_target_error_names_decorated_function() -> None: bad = PythonFunction(module="pkg.mod", qualname="") with pytest.raises(ValueError, match="my_named_stub"): - @action(InputEvent.EVENT_TYPE, target=bad) + @action(EventType.InputEvent, target=bad) def my_named_stub(event: Event, ctx: RunnerContext) -> None: pass diff --git a/python/flink_agents/api/tests/test_event_type.py b/python/flink_agents/api/tests/test_event_type.py new file mode 100644 index 000000000..a25e23fc8 --- /dev/null +++ b/python/flink_agents/api/tests/test_event_type.py @@ -0,0 +1,40 @@ +################################################################################ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################# +"""Smoke tests for :mod:`flink_agents.api.events.event_type`.""" + +from __future__ import annotations + +from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent +from flink_agents.api.events.context_retrieval_event import ( + ContextRetrievalRequestEvent, + ContextRetrievalResponseEvent, +) +from flink_agents.api.events.event import InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType +from flink_agents.api.events.tool_event import ToolRequestEvent, ToolResponseEvent + + +def test_builtin_constants_match_event_class_constants() -> None: + assert EventType.InputEvent == InputEvent.EVENT_TYPE + assert EventType.OutputEvent == OutputEvent.EVENT_TYPE + assert EventType.ChatRequestEvent == ChatRequestEvent.EVENT_TYPE + assert EventType.ChatResponseEvent == ChatResponseEvent.EVENT_TYPE + assert EventType.ToolRequestEvent == ToolRequestEvent.EVENT_TYPE + assert EventType.ToolResponseEvent == ToolResponseEvent.EVENT_TYPE + assert EventType.ContextRetrievalRequestEvent == ContextRetrievalRequestEvent.EVENT_TYPE + assert EventType.ContextRetrievalResponseEvent == ContextRetrievalResponseEvent.EVENT_TYPE diff --git a/python/flink_agents/api/yaml/loader.py b/python/flink_agents/api/yaml/loader.py index 54e5938e2..82303de97 100644 --- a/python/flink_agents/api/yaml/loader.py +++ b/python/flink_agents/api/yaml/loader.py @@ -168,9 +168,11 @@ def _resolve_action_function(action: ActionSpec) -> Function: def _add_action_to_agent(agent: Agent, action: ActionSpec) -> None: func = _resolve_action_function(action) - events = [resolve_event_type(e) for e in action.listen_to] + trigger_conditions = [ + resolve_event_type(e) for e in action.trigger_conditions + ] config = action.config or {} - agent.add_action(action.name, events, func, **config) + agent.add_action(action.name, trigger_conditions, func, **config) def _build_tool(spec: ToolSpec) -> FunctionTool: diff --git a/python/flink_agents/api/yaml/specs.py b/python/flink_agents/api/yaml/specs.py index cf99c66b9..2458b227f 100644 --- a/python/flink_agents/api/yaml/specs.py +++ b/python/flink_agents/api/yaml/specs.py @@ -172,12 +172,16 @@ def _require_one_source(self) -> "SkillsSpec": class ActionSpec(BaseModel): - """An action references a user function and the event types it listens to. + """An action references a user function and its trigger conditions. ``function`` is written as ``:`` — the colon separates the Python module (or Java class FQN) from the attribute path inside it. + ``trigger_conditions`` carries one or more strings. Each is either an + event-type name (bare identifier) or a future condition-expression + form — the runtime classifies the string when it loads the plan. + Action signatures are fixed (``(Event, RunnerContext)``), so there is no ``parameter_types`` knob — Python doesn't need it, and the Java action signature is determined by the action contract. @@ -187,7 +191,7 @@ class ActionSpec(BaseModel): name: str function: str | None = None - listen_to: List[str] = Field(..., min_length=1) + trigger_conditions: List[str] = Field(..., min_length=1) config: Dict[str, Any] | None = None type: Language | None = None diff --git a/python/flink_agents/api/yaml/tests/fixtures/multi_agent.yaml b/python/flink_agents/api/yaml/tests/fixtures/multi_agent.yaml index 5d8a30557..ba56be969 100644 --- a/python/flink_agents/api/yaml/tests/fixtures/multi_agent.yaml +++ b/python/flink_agents/api/yaml/tests/fixtures/multi_agent.yaml @@ -3,9 +3,9 @@ agents: actions: - name: increment function: flink_agents.api.yaml.tests.fixtures.loader_targets:increment - listen_to: [input] + trigger_conditions: [input] - name: a2 actions: - name: decrement function: flink_agents.api.yaml.tests.fixtures.loader_targets:decrement - listen_to: [input] \ No newline at end of file + trigger_conditions: [input] \ No newline at end of file diff --git a/python/flink_agents/api/yaml/tests/fixtures/multi_file_a.yaml b/python/flink_agents/api/yaml/tests/fixtures/multi_file_a.yaml index b876e39d7..8cd6ad43f 100644 --- a/python/flink_agents/api/yaml/tests/fixtures/multi_file_a.yaml +++ b/python/flink_agents/api/yaml/tests/fixtures/multi_file_a.yaml @@ -3,7 +3,7 @@ agents: actions: - name: increment function: flink_agents.api.yaml.tests.fixtures.loader_targets:increment - listen_to: [input] + trigger_conditions: [input] chat_model_connections: - name: conn_from_a clazz: ollama diff --git a/python/flink_agents/api/yaml/tests/fixtures/multi_file_b.yaml b/python/flink_agents/api/yaml/tests/fixtures/multi_file_b.yaml index d50f3c43f..23d1ae5f8 100644 --- a/python/flink_agents/api/yaml/tests/fixtures/multi_file_b.yaml +++ b/python/flink_agents/api/yaml/tests/fixtures/multi_file_b.yaml @@ -3,7 +3,7 @@ agents: actions: - name: decrement function: flink_agents.api.yaml.tests.fixtures.loader_targets:decrement - listen_to: [input] + trigger_conditions: [input] chat_model_connections: - name: conn_from_b clazz: ollama diff --git a/python/flink_agents/api/yaml/tests/fixtures/single_agent.yaml b/python/flink_agents/api/yaml/tests/fixtures/single_agent.yaml index e273feadb..833026bd6 100644 --- a/python/flink_agents/api/yaml/tests/fixtures/single_agent.yaml +++ b/python/flink_agents/api/yaml/tests/fixtures/single_agent.yaml @@ -3,4 +3,4 @@ agents: actions: - name: increment function: flink_agents.api.yaml.tests.fixtures.loader_targets:increment - listen_to: [input] \ No newline at end of file + trigger_conditions: [input] \ No newline at end of file diff --git a/python/flink_agents/api/yaml/tests/fixtures/with_descriptors.yaml b/python/flink_agents/api/yaml/tests/fixtures/with_descriptors.yaml index d43d5ad3a..710a8e318 100644 --- a/python/flink_agents/api/yaml/tests/fixtures/with_descriptors.yaml +++ b/python/flink_agents/api/yaml/tests/fixtures/with_descriptors.yaml @@ -3,10 +3,10 @@ agents: actions: - name: increment function: flink_agents.api.yaml.tests.fixtures.loader_targets:increment - listen_to: [input] + trigger_conditions: [input] - name: decrement function: flink_agents.api.yaml.tests.fixtures.loader_targets:decrement - listen_to: [chat_response] + trigger_conditions: [chat_response] chat_model_connections: - name: ollama_conn clazz: ollama diff --git a/python/flink_agents/api/yaml/tests/fixtures/with_shared.yaml b/python/flink_agents/api/yaml/tests/fixtures/with_shared.yaml index 26b0995cd..a7b25a6d3 100644 --- a/python/flink_agents/api/yaml/tests/fixtures/with_shared.yaml +++ b/python/flink_agents/api/yaml/tests/fixtures/with_shared.yaml @@ -4,7 +4,7 @@ agents: - shared_inc - name: own_dec function: flink_agents.api.yaml.tests.fixtures.loader_targets:decrement - listen_to: [chat_response] + trigger_conditions: [chat_response] - name: a2 actions: - shared_inc @@ -17,4 +17,4 @@ chat_model_connections: actions: - name: shared_inc function: flink_agents.api.yaml.tests.fixtures.loader_targets:increment - listen_to: [input] \ No newline at end of file + trigger_conditions: [input] \ No newline at end of file diff --git a/python/flink_agents/api/yaml/tests/test_loader.py b/python/flink_agents/api/yaml/tests/test_loader.py index 048c6b6a0..0b10b6bd1 100644 --- a/python/flink_agents/api/yaml/tests/test_loader.py +++ b/python/flink_agents/api/yaml/tests/test_loader.py @@ -112,12 +112,12 @@ def test_build_agents_rejects_duplicate_agent_within_file(tmp_path: Path) -> Non " actions:\n" " - name: increment\n" f" function: {_TARGETS_MODULE}:increment\n" - " listen_to: [input]\n" + " trigger_conditions: [input]\n" " - name: dup\n" " actions:\n" " - name: decrement\n" f" function: {_TARGETS_MODULE}:decrement\n" - " listen_to: [input]\n" + " trigger_conditions: [input]\n" ) p = tmp_path / "dup.yaml" p.write_text(yaml_text) @@ -295,9 +295,9 @@ def test_load_yaml_duplicate_shared_action_within_file_errors(tmp_path) -> None: " - name: a\n" "actions:\n" " - name: shared\n" - " listen_to: [input]\n" + " trigger_conditions: [input]\n" " - name: shared\n" - " listen_to: [input]\n" + " trigger_conditions: [input]\n" ) env = AgentsExecutionEnvironment.get_execution_environment() with pytest.raises(ValueError, match="Duplicate shared action name 'shared'"): @@ -525,7 +525,7 @@ def test_build_agents_builds_java_action(tmp_path: Path) -> None: " - name: a1\n" " type: java\n" " function: com.example.MyAgent:handle\n" - " listen_to: [input]\n" + " trigger_conditions: [input]\n" ) p = tmp_path / "java_action.yaml" p.write_text(yaml_text) @@ -554,7 +554,7 @@ def test_build_agents_rejects_java_tool_missing_parameter_types( " actions:\n" " - name: noop\n" f" function: {_TARGETS_MODULE}:increment\n" - " listen_to: [input]\n" + " trigger_conditions: [input]\n" ) p = tmp_path / "java_tool_no_params.yaml" p.write_text(yaml_text) @@ -578,7 +578,7 @@ def test_build_agents_rejects_python_tool_with_parameter_types( " actions:\n" " - name: noop\n" f" function: {_TARGETS_MODULE}:increment\n" - " listen_to: [input]\n" + " trigger_conditions: [input]\n" ) p = tmp_path / "python_tool_params.yaml" p.write_text(yaml_text) @@ -605,7 +605,7 @@ def test_build_agents_builds_java_tool_descriptor(tmp_path: Path) -> None: " actions:\n" " - name: noop\n" f" function: {_TARGETS_MODULE}:increment\n" - " listen_to: [input]\n" + " trigger_conditions: [input]\n" ) p = tmp_path / "java_tool.yaml" p.write_text(yaml_text) diff --git a/python/flink_agents/api/yaml/tests/test_specs.py b/python/flink_agents/api/yaml/tests/test_specs.py index 1c849f0fc..91a2c4c1e 100644 --- a/python/flink_agents/api/yaml/tests/test_specs.py +++ b/python/flink_agents/api/yaml/tests/test_specs.py @@ -139,49 +139,53 @@ def test_tool_spec_forbids_extras() -> None: ToolSpec.model_validate({"name": "t1", "unknown": 1}) -def test_action_spec_requires_listen_to() -> None: +def test_action_spec_requires_trigger_conditions() -> None: with pytest.raises(ValidationError): ActionSpec.model_validate({"name": "a1"}) -def test_action_spec_rejects_empty_listen_to() -> None: - # An empty ``listen_to: []`` would silently register a dead action that - # never fires. The minimum-length constraint forces the mistake to - # surface at YAML validation time. +def test_action_spec_rejects_empty_trigger_conditions() -> None: + # An empty ``trigger_conditions: []`` would silently register a dead + # action that never fires. The minimum-length constraint forces the + # mistake to surface at YAML validation time. with pytest.raises(ValidationError): - ActionSpec.model_validate({"name": "a1", "listen_to": []}) + ActionSpec.model_validate({"name": "a1", "trigger_conditions": []}) def test_action_spec_defaults() -> None: - spec = ActionSpec.model_validate({"name": "a1", "listen_to": ["input"]}) - assert spec.listen_to == ["input"] + spec = ActionSpec.model_validate( + {"name": "a1", "trigger_conditions": ["input"]} + ) + assert spec.trigger_conditions == ["input"] assert spec.function is None assert spec.config is None def test_action_spec_with_config() -> None: spec = ActionSpec.model_validate( - {"name": "a1", "listen_to": ["input"], "config": {"k": 1}} + {"name": "a1", "trigger_conditions": ["input"], "config": {"k": 1}} ) assert spec.config == {"k": 1} def test_action_spec_accepts_type() -> None: spec = ActionSpec.model_validate( - {"name": "a1", "listen_to": ["input"], "type": "java"} + {"name": "a1", "trigger_conditions": ["input"], "type": "java"} ) assert spec.type == "java" def test_action_spec_type_defaults_to_none() -> None: - spec = ActionSpec.model_validate({"name": "a1", "listen_to": ["input"]}) + spec = ActionSpec.model_validate( + {"name": "a1", "trigger_conditions": ["input"]} + ) assert spec.type is None def test_action_spec_rejects_unknown_type() -> None: with pytest.raises(ValidationError): ActionSpec.model_validate( - {"name": "a1", "listen_to": ["input"], "type": "rust"} + {"name": "a1", "trigger_conditions": ["input"], "type": "rust"} ) @@ -216,7 +220,7 @@ def test_agent_spec_action_can_be_string_reference() -> None: "name": "a", "actions": [ "shared_action1", - {"name": "x", "listen_to": ["input"]}, + {"name": "x", "trigger_conditions": ["input"]}, ], } ) @@ -245,7 +249,7 @@ def test_yaml_document_with_shared_resources_and_actions() -> None: { "agents": [{"name": "a"}], "chat_model_connections": [{"name": "c", "clazz": "x.Y"}], - "actions": [{"name": "shared", "listen_to": ["input"]}], + "actions": [{"name": "shared", "trigger_conditions": ["input"]}], } ) assert doc.chat_model_connections[0].name == "c" @@ -321,7 +325,7 @@ def test_action_spec_rejects_parameter_types() -> None: ActionSpec.model_validate( { "name": "a1", - "listen_to": ["input"], + "trigger_conditions": ["input"], "type": "java", "parameter_types": ["x.Y"], } diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/agent_skills_test.py b/python/flink_agents/e2e_tests/e2e_tests_integration/agent_skills_test.py index 8e5d13f8a..2fdc42354 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/agent_skills_test.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/agent_skills_test.py @@ -42,6 +42,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ResourceDescriptor, ResourceName, ResourceType @@ -107,7 +108,7 @@ def system_prompt() -> Prompt: ], ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: input_event = InputEvent.from_event(event) @@ -138,7 +139,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: chat_response = ChatResponseEvent.from_event(event) diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/built_in_action_async_execution_test.py b/python/flink_agents/e2e_tests/e2e_tests_integration/built_in_action_async_execution_test.py index f59d25f00..cb0de86ee 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/built_in_action_async_execution_test.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/built_in_action_async_execution_test.py @@ -28,6 +28,7 @@ from flink_agents.api.decorators import action, chat_model_setup, tool from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.resource import ResourceDescriptor from flink_agents.api.runner_context import RunnerContext @@ -83,7 +84,7 @@ def add(a: int, b: int) -> int: time.sleep(5) # Simulate slow tool execution return a + b - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: input_event = InputEvent.from_event(event) @@ -96,7 +97,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: input = ChatResponseEvent.from_event(event).response diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/chat_model_integration_agent.py b/python/flink_agents/e2e_tests/e2e_tests_integration/chat_model_integration_agent.py index 2b9b7da70..c7158dbd1 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/chat_model_integration_agent.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/chat_model_integration_agent.py @@ -27,6 +27,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.resource import ( ResourceDescriptor, ResourceName, @@ -162,7 +163,7 @@ def add(a: int, b: int) -> int: """ return a + b - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """User defined action for processing input. @@ -183,7 +184,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """User defined action for processing chat model response.""" diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/e2e_tests_mcp/mcp_test.py b/python/flink_agents/e2e_tests/e2e_tests_integration/e2e_tests_mcp/mcp_test.py index b617e825a..2c994f1fb 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/e2e_tests_mcp/mcp_test.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/e2e_tests_mcp/mcp_test.py @@ -46,6 +46,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.resource import ( ResourceDescriptor, @@ -106,7 +107,7 @@ def math_chat_model() -> ResourceDescriptor: ) return ResourceDescriptor(**descriptor_kwargs) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input and send chat request. @@ -136,7 +137,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ctx.send_event(ChatRequestEvent(model="math_chat_model", messages=[msg])) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat response and output result.""" diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/execute_test_agent.py b/python/flink_agents/e2e_tests/e2e_tests_integration/execute_test_agent.py index c1f5aa50b..6bd662f41 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/execute_test_agent.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/execute_test_agent.py @@ -23,6 +23,7 @@ from flink_agents.api.agents.agent import Agent from flink_agents.api.decorators import action from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.runner_context import RunnerContext @@ -97,7 +98,7 @@ def raise_exception(message: str) -> None: class ExecuteTestAgent(Agent): """Agent that uses synchronous durable_execute() method for testing.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process(event: Event, ctx: RunnerContext) -> None: """Process an event using durable_execute().""" @@ -112,7 +113,7 @@ def process(event: Event, ctx: RunnerContext) -> None: class ExecuteMultipleTestAgent(Agent): """Agent that makes multiple durable_execute() calls.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process(event: Event, ctx: RunnerContext) -> None: """Process an event with multiple durable_execute() calls.""" @@ -127,7 +128,7 @@ def process(event: Event, ctx: RunnerContext) -> None: class ExecuteWithAsyncTestAgent(Agent): """Agent that uses both durable_execute() and durable_execute_async().""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod async def process(event: Event, ctx: RunnerContext) -> None: """Process an event using both durable_execute() and durable_execute_async().""" @@ -144,7 +145,7 @@ async def process(event: Event, ctx: RunnerContext) -> None: class ExecuteWithAsyncExceptionTestAgent(Agent): """Agent that tests exception handling in durable_execute_async().""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod async def process(event: Event, ctx: RunnerContext) -> None: """Process an event and capture durable_execute_async() exceptions.""" diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/flink_integration_agent.py b/python/flink_agents/e2e_tests/e2e_tests_integration/flink_integration_agent.py index 744eb9d95..b464754f5 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/flink_integration_agent.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/flink_integration_agent.py @@ -27,6 +27,7 @@ from flink_agents.api.agents.agent import Agent from flink_agents.api.decorators import action, tool from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.resource import ResourceType from flink_agents.api.runner_context import RunnerContext @@ -105,7 +106,7 @@ def my_tool(input: str) -> str: """ return input + " call my tool" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod async def first_action(event: Event, ctx: RunnerContext) -> None: def log_to_stdout(input: Any, total: int) -> bool: @@ -154,7 +155,7 @@ class TableAgent(Agent): to __main__. """ - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def first_action(event: Event, ctx: RunnerContext) -> None: content = InputEvent.from_event(event).input @@ -177,7 +178,7 @@ class DataStreamToTableAgent(Agent): to __main__. """ - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def first_action(event: Event, ctx: RunnerContext) -> None: content = ItemData.model_validate(InputEvent.from_event(event).input) diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/long_term_memory_test.py b/python/flink_agents/e2e_tests/e2e_tests_integration/long_term_memory_test.py index a5dc32836..3db2ae010 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/long_term_memory_test.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/long_term_memory_test.py @@ -53,6 +53,7 @@ vector_store, ) from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.memory.long_term_memory import ( LongTermMemoryOptions, @@ -189,7 +190,7 @@ def chroma_ltm_store() -> ResourceDescriptor: collection="context", ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod async def add_items(event: Event, ctx: RunnerContext) -> None: input_data = ItemData.model_validate(InputEvent.from_event(event).input) diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/python_event_logging_test.py b/python/flink_agents/e2e_tests/e2e_tests_integration/python_event_logging_test.py index 898079276..2aade7d80 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/python_event_logging_test.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/python_event_logging_test.py @@ -36,6 +36,7 @@ from flink_agents.api.agents.agent import Agent from flink_agents.api.decorators import action from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.runner_context import RunnerContext @@ -53,7 +54,7 @@ def get_key(self, value: dict) -> int: class PythonEventLoggingAgent(Agent): """Agent for testing Python event logging.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event and send an output event.""" diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/short_term_memory_ttl_test.py b/python/flink_agents/e2e_tests/e2e_tests_integration/short_term_memory_ttl_test.py index 19c149fc9..472c12ae5 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/short_term_memory_ttl_test.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/short_term_memory_ttl_test.py @@ -33,6 +33,7 @@ ) from flink_agents.api.decorators import action from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.runner_context import RunnerContext @@ -53,7 +54,7 @@ def get_key(self, value: TtlTestInput) -> str: class ShortTermMemoryTtlTestAgent(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def input(event: Event, ctx: RunnerContext) -> None: input_data = TtlTestInput.model_validate(InputEvent.from_event(event).input) diff --git a/python/flink_agents/e2e_tests/e2e_tests_integration/workflow_test.py b/python/flink_agents/e2e_tests/e2e_tests_integration/workflow_test.py index 2eafea7c1..477424b66 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_integration/workflow_test.py +++ b/python/flink_agents/e2e_tests/e2e_tests_integration/workflow_test.py @@ -24,6 +24,7 @@ from flink_agents.api.agents.agent import Agent from flink_agents.api.decorators import action from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.runner_context import RunnerContext @@ -68,7 +69,7 @@ class MyAgent(Agent): validation. """ - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def first_action(event: Event, ctx: RunnerContext) -> None: key = ctx.key diff --git a/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/chat_model_cross_language_agent.py b/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/chat_model_cross_language_agent.py index 2aca6a2bd..3920f2389 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/chat_model_cross_language_agent.py +++ b/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/chat_model_cross_language_agent.py @@ -28,6 +28,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ( ResourceDescriptor, @@ -129,7 +130,7 @@ def add(a: int, b: int) -> int: """ return a + b - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """User defined action for processing input. @@ -150,7 +151,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """User defined action for processing chat model response.""" diff --git a/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/embedding_model_cross_language_agent.py b/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/embedding_model_cross_language_agent.py index 9a2ba4ed9..dbce4891b 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/embedding_model_cross_language_agent.py +++ b/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/embedding_model_cross_language_agent.py @@ -24,6 +24,7 @@ embedding_model_setup, ) from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.resource import ( ResourceDescriptor, ResourceName, @@ -56,7 +57,7 @@ def embedding_model() -> ResourceDescriptor: model=os.environ.get("OLLAMA_EMBEDDING_MODEL", "nomic-embed-text:latest"), ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """User defined action for processing input. diff --git a/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/python_agent_with_java_action.py b/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/python_agent_with_java_action.py index f7fb2160b..1f33d1f6d 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/python_agent_with_java_action.py +++ b/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/python_agent_with_java_action.py @@ -35,7 +35,7 @@ def __init__(self) -> None: super().__init__() self.add_action( name="multiply_by_two", - events=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], func=JavaFunction.for_action(JAVA_HANDLER_QUALNAME, JAVA_HANDLER_METHOD), ) diff --git a/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/vector_store_cross_language_agent.py b/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/vector_store_cross_language_agent.py index 18671bea2..52000147a 100644 --- a/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/vector_store_cross_language_agent.py +++ b/python/flink_agents/e2e_tests/e2e_tests_resource_cross_language/vector_store_cross_language_agent.py @@ -30,6 +30,7 @@ ContextRetrievalResponseEvent, ) from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.resource import ( ResourceDescriptor, ResourceName, @@ -153,7 +154,7 @@ def vector_store() -> ResourceDescriptor: msg = f"Unsupported vector store backend: {backend}" raise ValueError(msg) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """User defined action for processing input. @@ -273,7 +274,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ContextRetrievalResponseEvent.EVENT_TYPE) + @action(EventType.ContextRetrievalResponseEvent) @staticmethod def contextRetrievalResponseEvent(event: Event, ctx: RunnerContext) -> None: """User defined action for processing context retrieval response. diff --git a/python/flink_agents/e2e_tests/resources/yaml_cross_language_actions_in_java.yaml b/python/flink_agents/e2e_tests/resources/yaml_cross_language_actions_in_java.yaml index b7acca473..9f2029e46 100644 --- a/python/flink_agents/e2e_tests/resources/yaml_cross_language_actions_in_java.yaml +++ b/python/flink_agents/e2e_tests/resources/yaml_cross_language_actions_in_java.yaml @@ -42,8 +42,8 @@ agents: - name: process_input type: java function: org.apache.flink.agents.resource.test.YamlCrossLanguageActions:processInput - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response type: java function: org.apache.flink.agents.resource.test.YamlCrossLanguageActions:processChatResponse - listen_to: [chat_response] + trigger_conditions: [chat_response] diff --git a/python/flink_agents/e2e_tests/resources/yaml_cross_language_agent.yaml b/python/flink_agents/e2e_tests/resources/yaml_cross_language_agent.yaml index decebe129..f53733681 100644 --- a/python/flink_agents/e2e_tests/resources/yaml_cross_language_agent.yaml +++ b/python/flink_agents/e2e_tests/resources/yaml_cross_language_agent.yaml @@ -42,7 +42,7 @@ agents: actions: - name: process_input function: flink_agents.e2e_tests.e2e_tests_resource_cross_language.yaml_cross_language_actions:process_input - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response function: flink_agents.e2e_tests.e2e_tests_resource_cross_language.yaml_cross_language_actions:process_chat_response - listen_to: [chat_response] \ No newline at end of file + trigger_conditions: [chat_response] \ No newline at end of file diff --git a/python/flink_agents/e2e_tests/resources/yaml_cross_language_java_action.yaml b/python/flink_agents/e2e_tests/resources/yaml_cross_language_java_action.yaml index d6c9029bb..7eea45905 100644 --- a/python/flink_agents/e2e_tests/resources/yaml_cross_language_java_action.yaml +++ b/python/flink_agents/e2e_tests/resources/yaml_cross_language_java_action.yaml @@ -12,4 +12,4 @@ agents: - name: multiply_by_two type: java function: org.apache.flink.agents.resource.test.JavaActionHandler:multiplyByTwo - listen_to: [input] + trigger_conditions: [input] diff --git a/python/flink_agents/e2e_tests/resources/yaml_multi_agent.yaml b/python/flink_agents/e2e_tests/resources/yaml_multi_agent.yaml index 06d0138ac..9c362cf67 100644 --- a/python/flink_agents/e2e_tests/resources/yaml_multi_agent.yaml +++ b/python/flink_agents/e2e_tests/resources/yaml_multi_agent.yaml @@ -14,7 +14,7 @@ agents: actions: - name: chat_request function: flink_agents.e2e_tests.e2e_tests_integration.yaml_test_actions:chat_request - listen_to: [input] + trigger_conditions: [input] - process_chat_response - name: commentator_agent @@ -31,7 +31,7 @@ agents: actions: - name: commentary_request function: flink_agents.e2e_tests.e2e_tests_integration.yaml_test_actions:commentary_request - listen_to: [input] + trigger_conditions: [input] - process_chat_response # File-level shared resources reused by every agent above. @@ -43,4 +43,4 @@ chat_model_connections: actions: - name: process_chat_response function: flink_agents.e2e_tests.e2e_tests_integration.yaml_test_actions:process_chat_response - listen_to: [chat_response] \ No newline at end of file + trigger_conditions: [chat_response] \ No newline at end of file diff --git a/python/flink_agents/e2e_tests/resources/yaml_test_agent.yaml b/python/flink_agents/e2e_tests/resources/yaml_test_agent.yaml index 6c29f5089..aa2e153c1 100644 --- a/python/flink_agents/e2e_tests/resources/yaml_test_agent.yaml +++ b/python/flink_agents/e2e_tests/resources/yaml_test_agent.yaml @@ -26,7 +26,7 @@ agents: actions: - name: process_input function: flink_agents.e2e_tests.e2e_tests_integration.yaml_test_actions:process_input - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response function: flink_agents.e2e_tests.e2e_tests_integration.yaml_test_actions:process_chat_response - listen_to: [chat_response] \ No newline at end of file + trigger_conditions: [chat_response] \ No newline at end of file diff --git a/python/flink_agents/examples/quickstart/agents/math_agent.py b/python/flink_agents/examples/quickstart/agents/math_agent.py index 20e3b8acf..77f177607 100644 --- a/python/flink_agents/examples/quickstart/agents/math_agent.py +++ b/python/flink_agents/examples/quickstart/agents/math_agent.py @@ -20,6 +20,7 @@ from flink_agents.api.decorators import action, chat_model_setup, prompt, skills from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ResourceDescriptor, ResourceName from flink_agents.api.runner_context import RunnerContext @@ -79,7 +80,7 @@ def math_model() -> ResourceDescriptor: allowed_commands=["echo", "bc"], ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event and send a chat request to evaluate the question.""" @@ -91,7 +92,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat response event and send the answer as output.""" diff --git a/python/flink_agents/examples/quickstart/agents/product_suggestion_agent.py b/python/flink_agents/examples/quickstart/agents/product_suggestion_agent.py index 20350835a..b0979fa76 100644 --- a/python/flink_agents/examples/quickstart/agents/product_suggestion_agent.py +++ b/python/flink_agents/examples/quickstart/agents/product_suggestion_agent.py @@ -26,6 +26,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ResourceDescriptor, ResourceName from flink_agents.api.runner_context import RunnerContext @@ -66,7 +67,7 @@ def generate_suggestion_model() -> ResourceDescriptor: extract_reasoning=True, ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event.""" @@ -87,7 +88,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat response event.""" diff --git a/python/flink_agents/examples/quickstart/agents/review_analysis_agent.py b/python/flink_agents/examples/quickstart/agents/review_analysis_agent.py index 8bd3b74dc..8e7f9a105 100644 --- a/python/flink_agents/examples/quickstart/agents/review_analysis_agent.py +++ b/python/flink_agents/examples/quickstart/agents/review_analysis_agent.py @@ -27,6 +27,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ResourceDescriptor, ResourceName from flink_agents.api.runner_context import RunnerContext @@ -83,7 +84,7 @@ def review_analysis_model() -> ResourceDescriptor: extract_reasoning=True, ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event and send chat request for review analysis.""" @@ -103,7 +104,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat response event and send output event.""" diff --git a/python/flink_agents/examples/quickstart/agents/table_review_analysis_agent.py b/python/flink_agents/examples/quickstart/agents/table_review_analysis_agent.py index 1ee1f801c..7ddf94390 100644 --- a/python/flink_agents/examples/quickstart/agents/table_review_analysis_agent.py +++ b/python/flink_agents/examples/quickstart/agents/table_review_analysis_agent.py @@ -31,6 +31,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ResourceDescriptor, ResourceName from flink_agents.api.runner_context import RunnerContext @@ -108,7 +109,7 @@ def review_analysis_model() -> ResourceDescriptor: extract_reasoning=True, ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process input event from Table data (dictionary format). @@ -135,7 +136,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat response event and send output event.""" diff --git a/python/flink_agents/examples/quickstart/yaml_review_analysis_agent.yaml b/python/flink_agents/examples/quickstart/yaml_review_analysis_agent.yaml index f6aff0a87..727891163 100644 --- a/python/flink_agents/examples/quickstart/yaml_review_analysis_agent.yaml +++ b/python/flink_agents/examples/quickstart/yaml_review_analysis_agent.yaml @@ -9,10 +9,10 @@ agents: actions: - name: process_input function: flink_agents.examples.quickstart.agents.review_analysis_agent:ReviewAnalysisAgent.process_input - listen_to: [input] + trigger_conditions: [input] - name: process_chat_response function: flink_agents.examples.quickstart.agents.review_analysis_agent:ReviewAnalysisAgent.process_chat_response - listen_to: [chat_response] + trigger_conditions: [chat_response] chat_model_connections: - name: ollama_server diff --git a/python/flink_agents/examples/rag/rag_agent_example.py b/python/flink_agents/examples/rag/rag_agent_example.py index de1d9ebe6..6972cdf43 100644 --- a/python/flink_agents/examples/rag/rag_agent_example.py +++ b/python/flink_agents/examples/rag/rag_agent_example.py @@ -32,6 +32,7 @@ ContextRetrievalResponseEvent, ) from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ( @@ -103,7 +104,7 @@ def chat_model() -> ResourceDescriptor: model=OLLAMA_CHAT_MODEL, ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """Process user input and retrieve relevant context.""" @@ -116,7 +117,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ContextRetrievalResponseEvent.EVENT_TYPE) + @action(EventType.ContextRetrievalResponseEvent) @staticmethod def process_retrieved_context( event: Event, ctx: RunnerContext @@ -147,7 +148,7 @@ def process_retrieved_context( ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """Process chat model response and generate output.""" diff --git a/python/flink_agents/plan/actions/action.py b/python/flink_agents/plan/actions/action.py index 96f2f5f0a..c3ad31457 100644 --- a/python/flink_agents/plan/actions/action.py +++ b/python/flink_agents/plan/actions/action.py @@ -29,10 +29,10 @@ class Action(BaseModel): - """Representation of an agent action with event listening and function execution. + """Representation of an agent action with unified trigger conditions. - This class encapsulates a named agent action that listens for specific event - types and executes an associated function when those events occur. + This class encapsulates a named agent action that triggers on matching + events and executes an associated function. Attributes: ---------- @@ -40,8 +40,9 @@ class Action(BaseModel): Name/identifier of the agent Action. exec : Function To be executed when the Action is triggered. - listen_event_types : List[str] - List of event types that will trigger this Action's execution. + trigger_conditions : List[str] + Event-type name strings that will trigger this Action. Multiple + entries combine with OR semantics. """ model_config = ConfigDict(arbitrary_types_allowed=True) @@ -49,9 +50,18 @@ class Action(BaseModel): name: str # TODO: Raise a warning when the action has a return value, as it will be ignored. exec: PythonFunction | JavaFunction - listen_event_types: List[str] + trigger_conditions: List[str] config: Dict[str, Any] | None = None + @property + def listen_event_types(self) -> List[str]: + """Event-type names. Kept for callers that still consume the old naming; + in this PR all entries are plain event-type names so the list is + identical to ``trigger_conditions``. A follow-up PR introduces CEL + expressions and overrides this to filter out non-type entries. + """ + return self.trigger_conditions + @field_serializer("config") def __serialize_config(self, config: Dict[str, Any]) -> Dict[str, Any] | None: if config is None: @@ -71,7 +81,7 @@ def __serialize_config(self, config: Dict[str, Any]) -> Dict[str, Any] | None: @model_validator(mode="before") def __custom_deserialize(self) -> "Action": - config = self["config"] + config = self.get("config") if config is None or _CONFIG_TYPE not in config: return self config_type = self["config"].pop(_CONFIG_TYPE) @@ -97,12 +107,12 @@ def __init__( self, name: str, exec: Function, - listen_event_types: List[str], + trigger_conditions: List[str], config: Dict[str, Any] | None = None, ) -> None: """Action will check function signature when init.""" super().__init__( - name=name, exec=exec, listen_event_types=listen_event_types, config=config + name=name, exec=exec, trigger_conditions=trigger_conditions, config=config ) # TODO: Update expected signature after import State and Context. self.exec.check_signature(Event, RunnerContext) diff --git a/python/flink_agents/plan/actions/chat_model_action.py b/python/flink_agents/plan/actions/chat_model_action.py index e4572056e..de67881b3 100644 --- a/python/flink_agents/plan/actions/chat_model_action.py +++ b/python/flink_agents/plan/actions/chat_model_action.py @@ -475,7 +475,7 @@ async def process_chat_request_or_tool_response( CHAT_MODEL_ACTION = Action( name="chat_model_action", exec=PythonFunction.from_callable(process_chat_request_or_tool_response), - listen_event_types=[ + trigger_conditions=[ ChatRequestEvent.EVENT_TYPE, ToolResponseEvent.EVENT_TYPE, ], diff --git a/python/flink_agents/plan/actions/context_retrieval_action.py b/python/flink_agents/plan/actions/context_retrieval_action.py index d65f6d7f1..70d45ec3f 100644 --- a/python/flink_agents/plan/actions/context_retrieval_action.py +++ b/python/flink_agents/plan/actions/context_retrieval_action.py @@ -64,5 +64,5 @@ async def process_context_retrieval_request(event: Event, ctx: RunnerContext) -> CONTEXT_RETRIEVAL_ACTION = Action( name="context_retrieval_action", exec=PythonFunction.from_callable(process_context_retrieval_request), - listen_event_types=[ContextRetrievalRequestEvent.EVENT_TYPE], + trigger_conditions=[ContextRetrievalRequestEvent.EVENT_TYPE], ) diff --git a/python/flink_agents/plan/actions/tool_call_action.py b/python/flink_agents/plan/actions/tool_call_action.py index 6c7aaf270..1c8a8ce7d 100644 --- a/python/flink_agents/plan/actions/tool_call_action.py +++ b/python/flink_agents/plan/actions/tool_call_action.py @@ -63,5 +63,5 @@ async def process_tool_request(event: Event, ctx: RunnerContext) -> None: TOOL_CALL_ACTION = Action( name="tool_call_action", exec=PythonFunction.from_callable(process_tool_request), - listen_event_types=[ToolRequestEvent.EVENT_TYPE], + trigger_conditions=[ToolRequestEvent.EVENT_TYPE], ) diff --git a/python/flink_agents/plan/agent_plan.py b/python/flink_agents/plan/agent_plan.py index 24aca0caf..749a83f3f 100644 --- a/python/flink_agents/plan/agent_plan.py +++ b/python/flink_agents/plan/agent_plan.py @@ -145,7 +145,7 @@ def from_agent(agent: Agent, config: AgentConfiguration) -> "AgentPlan": for action in _get_actions(agent) + BUILT_IN_ACTIONS: assert action.name not in actions, f"Duplicate action name: {action.name}" actions[action.name] = action - for event_type in action.listen_event_types: + for event_type in action.trigger_conditions: if event_type not in actions_by_event: actions_by_event[event_type] = [] actions_by_event[event_type].append(action.name) @@ -227,9 +227,9 @@ def _resolve_event_type(evt: Any) -> str: def _action_marker(value: Any) -> tuple | None: - """Return ``(inner_callable, listen_events, target)`` if ``value`` is an @action. + """Return ``(inner_callable, trigger_conditions, target)`` if ``value`` is @action. - ``@action`` may set ``_listen_events`` on the outer wrapper (when ``@action`` + ``@action`` may set ``_trigger_conditions`` on the outer wrapper (when ``@action`` is the outer decorator) or on ``__func__`` (when ``@staticmethod`` is outer and ``@action`` inner). Accept either by checking both candidates. """ @@ -238,14 +238,14 @@ def _action_marker(value: Any) -> tuple | None: return None marker = ( value - if hasattr(value, "_listen_events") + if hasattr(value, "_trigger_conditions") else inner - if hasattr(inner, "_listen_events") + if hasattr(inner, "_trigger_conditions") else None ) if marker is None: return None - return inner, marker._listen_events, getattr(marker, "_target", None) + return inner, marker._trigger_conditions, getattr(marker, "_target", None) def _get_actions(agent: Agent) -> List[Action]: @@ -279,7 +279,7 @@ def _get_actions(agent: Agent) -> List[Action]: marker = _action_marker(value) if marker is None: continue - inner, listen_events, target = marker + inner, trigger_conditions, target = marker exec_ = ( _to_plan_function(target) if target is not None @@ -289,7 +289,9 @@ def _get_actions(agent: Agent) -> List[Action]: Action( name=name, exec=exec_, - listen_event_types=[_resolve_event_type(et) for et in listen_events], + trigger_conditions=[ + _resolve_event_type(et) for et in trigger_conditions + ], ) ) for name, action_tuple in agent.actions.items(): @@ -297,7 +299,7 @@ def _get_actions(agent: Agent) -> List[Action]: Action( name=name, exec=_to_plan_function(action_tuple[1]), - listen_event_types=[ + trigger_conditions=[ _resolve_event_type(et) for et in action_tuple[0] ], diff --git a/python/flink_agents/plan/tests/compatibility/create_python_agent_plan_from_json.py b/python/flink_agents/plan/tests/compatibility/create_python_agent_plan_from_json.py index c4397a84c..21096bc3d 100644 --- a/python/flink_agents/plan/tests/compatibility/create_python_agent_plan_from_json.py +++ b/python/flink_agents/plan/tests/compatibility/create_python_agent_plan_from_json.py @@ -51,7 +51,7 @@ event, runner_context, ] - listen_event_types1 = action1.listen_event_types + listen_event_types1 = action1.trigger_conditions assert listen_event_types1 == [input_event] # check the second action @@ -65,7 +65,7 @@ event, runner_context, ] - listen_event_types2 = action2.listen_event_types + listen_event_types2 = action2.trigger_conditions assert sorted(listen_event_types2) == [ my_event, input_event, diff --git a/python/flink_agents/plan/tests/compatibility/python_agent_plan_compatibility_test_agent.py b/python/flink_agents/plan/tests/compatibility/python_agent_plan_compatibility_test_agent.py index 5080cefbe..dca9197ca 100644 --- a/python/flink_agents/plan/tests/compatibility/python_agent_plan_compatibility_test_agent.py +++ b/python/flink_agents/plan/tests/compatibility/python_agent_plan_compatibility_test_agent.py @@ -21,7 +21,8 @@ from flink_agents.api.chat_message import ChatMessage from flink_agents.api.chat_models.chat_model import BaseChatModelSetup from flink_agents.api.decorators import action, chat_model_setup, tool -from flink_agents.api.events.event import Event, InputEvent +from flink_agents.api.events.event import Event +from flink_agents.api.events.event_type import EventType from flink_agents.api.resource import ResourceDescriptor from flink_agents.api.runner_context import RunnerContext @@ -51,7 +52,7 @@ def chat(self, messages: Sequence[ChatMessage], **kwargs: Any) -> ChatMessage: class PythonAgentPlanCompatibilityTestAgent(Agent): """Agent for generating python agent plan json.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def first_action(event: Event, ctx: RunnerContext) -> None: """Test implementation.""" diff --git a/python/flink_agents/plan/tests/resources/action.json b/python/flink_agents/plan/tests/resources/action.json index 7ec09d6c0..09393e475 100644 --- a/python/flink_agents/plan/tests/resources/action.json +++ b/python/flink_agents/plan/tests/resources/action.json @@ -5,7 +5,7 @@ "module": "flink_agents.plan.tests.test_action", "qualname": "legal_signature" }, - "listen_event_types": [ + "trigger_conditions": [ "_input_event" ], "config": { diff --git a/python/flink_agents/plan/tests/resources/agent_plan.json b/python/flink_agents/plan/tests/resources/agent_plan.json index 9f9a3f416..6e545ab1d 100644 --- a/python/flink_agents/plan/tests/resources/agent_plan.json +++ b/python/flink_agents/plan/tests/resources/agent_plan.json @@ -7,7 +7,7 @@ "module": "flink_agents.plan.tests.test_agent_plan", "qualname": "MyAgent.first_action" }, - "listen_event_types": [ + "trigger_conditions": [ "_input_event" ], "config": null @@ -19,7 +19,7 @@ "module": "flink_agents.plan.tests.test_agent_plan", "qualname": "MyAgent.second_action" }, - "listen_event_types": [ + "trigger_conditions": [ "_input_event", "_my_event" ], @@ -32,7 +32,7 @@ "module": "flink_agents.plan.actions.chat_model_action", "qualname": "process_chat_request_or_tool_response" }, - "listen_event_types": [ + "trigger_conditions": [ "_chat_request_event", "_tool_response_event" ], @@ -45,7 +45,7 @@ "module": "flink_agents.plan.actions.tool_call_action", "qualname": "process_tool_request" }, - "listen_event_types": [ + "trigger_conditions": [ "_tool_request_event" ], "config": null @@ -57,7 +57,7 @@ "module": "flink_agents.plan.actions.context_retrieval_action", "qualname": "process_context_retrieval_request" }, - "listen_event_types": [ + "trigger_conditions": [ "_context_retrieval_request_event" ], "config": null diff --git a/python/flink_agents/plan/tests/test_action.py b/python/flink_agents/plan/tests/test_action.py index 5a75f7186..f93ee4531 100644 --- a/python/flink_agents/plan/tests/test_action.py +++ b/python/flink_agents/plan/tests/test_action.py @@ -40,7 +40,7 @@ def test_action_signature_legal() -> None: Action( name="legal", exec=PythonFunction.from_callable(legal_signature), - listen_event_types=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], ) @@ -49,7 +49,7 @@ def test_action_signature_illegal() -> None: Action( name="illegal", exec=PythonFunction.from_callable(illegal_signature), - listen_event_types=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], ) @@ -59,7 +59,7 @@ def action() -> Action: return Action( name="legal", exec=func, - listen_event_types=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], config={ "output_schema": OutputSchema( output_schema=RowTypeInfo( @@ -88,7 +88,7 @@ def test_action_deserialize(action: Action) -> None: expected_json = f.read() action = Action.model_validate_json(expected_json) assert action.name == "legal" - assert action.listen_event_types == ["_input_event"] + assert action.trigger_conditions== ["_input_event"] func = action.exec assert func.module == "flink_agents.plan.tests.test_action" assert func.qualname == "legal_signature" @@ -103,7 +103,7 @@ def test_action_deserialize_java_shape_config_unwraps_primitives() -> None: "module": "flink_agents.plan.tests.test_action", "qualname": "legal_signature", }, - "listen_event_types": ["_input_event"], + "trigger_conditions": ["_input_event"], "config": { "__config_type__": "java", "timeout_sec": {"@class": "java.lang.Integer", "value": 30}, diff --git a/python/flink_agents/plan/tests/test_agent_plan.py b/python/flink_agents/plan/tests/test_agent_plan.py index 9d68f8c1b..7633f3d34 100644 --- a/python/flink_agents/plan/tests/test_agent_plan.py +++ b/python/flink_agents/plan/tests/test_agent_plan.py @@ -36,6 +36,7 @@ BaseEmbeddingModelSetup, ) from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.function import JavaFunction from flink_agents.api.resource import ResourceDescriptor, ResourceType from flink_agents.api.runner_context import RunnerContext @@ -50,7 +51,7 @@ class AgentForTest(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def increment(event: Event, ctx: RunnerContext) -> None: value = InputEvent.from_event(event).input @@ -69,11 +70,11 @@ def test_from_agent(): assert isinstance(func, PythonFunction) assert func.module == "flink_agents.plan.tests.test_agent_plan" assert func.qualname == "AgentForTest.increment" - assert action.listen_event_types == [InputEvent.EVENT_TYPE] + assert action.trigger_conditions == [InputEvent.EVENT_TYPE] class InvalidAgent(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def invalid_signature_action(event: Event) -> None: pass @@ -96,13 +97,13 @@ def test_builtin_actions_are_python_native_after_compile() -> None: class AgentWithConventionalDecoratorOrder(Agent): """`@staticmethod` outer, `@action` inner — the conventional Python order. - The decorator stack puts ``_listen_events`` on the inner function (i.e. + The decorator stack puts ``_trigger_conditions`` on the inner function (i.e. ``staticmethod.__func__``) rather than on the staticmethod wrapper, so ``_get_actions`` must unwrap before inspecting attributes. """ @staticmethod - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) def handle(event: Event, ctx: RunnerContext) -> None: ctx.send_event(OutputEvent(output=InputEvent.from_event(event).input)) @@ -115,7 +116,7 @@ def test_conventional_staticmethod_outer_decorator_order_is_registered() -> None assert len(actions) == 1, ( "Action defined with `@staticmethod` outer / `@action` inner was silently " "dropped — `_get_actions` should unwrap the staticmethod before checking " - "for `_listen_events`." + "for `_trigger_conditions`." ) assert actions[0].name == "handle" @@ -123,7 +124,7 @@ def test_conventional_staticmethod_outer_decorator_order_is_registered() -> None class _BaseAgentWithInheritedAction(Agent): """Base class with an @action — used to verify the inheritance guard.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def shared_action(event: Event, ctx: RunnerContext) -> None: ctx.send_event(OutputEvent(output="shared")) @@ -148,7 +149,7 @@ def test_action_inherited_from_parent_agent_class_is_rejected() -> None: class AgentWithCrossLanguageDecoratedAction(Agent): @action( - InputEvent.EVENT_TYPE, + EventType.InputEvent, target=JavaFunction.for_action(_JAVA_HANDLER_QUALNAME, "handleInput"), ) @staticmethod @@ -164,7 +165,7 @@ def test_decorated_action_with_target_compiles_to_plan_java_function() -> None: action = plan.actions["handle"] assert action.exec.qualname == _JAVA_HANDLER_QUALNAME assert action.exec.method_name == "handleInput" - assert action.listen_event_types == [InputEvent.EVENT_TYPE] + assert action.trigger_conditions == [InputEvent.EVENT_TYPE] class MyEvent(Event): @@ -319,7 +320,7 @@ def mock_vector_store() -> ResourceDescriptor: collection_name="test_collection", ) - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def first_action(event: Event, ctx: RunnerContext) -> None: pass @@ -369,10 +370,10 @@ def test_get_resource() -> None: def test_add_action_and_resource_to_agent() -> None: my_agent = Agent() my_agent.add_action( - name="first_action", events=["_input_event"], func=MyAgent.first_action + name="first_action", trigger_conditions=["_input_event"], func=MyAgent.first_action ) my_agent.add_action( - name="second_action", events=["_input_event", "_my_event"], func=MyAgent.second_action + name="second_action", trigger_conditions=["_input_event", "_my_event"], func=MyAgent.second_action ) my_agent.add_resource( name="mock", @@ -446,7 +447,7 @@ def test_from_agent_with_string_identifier() -> None: actions = agent_plan.get_actions("CustomEvent") assert len(actions) == 1 assert actions[0].name == "handle_custom" - assert "CustomEvent" in actions[0].listen_event_types + assert "CustomEvent" in actions[0].trigger_conditions # Verify serialization roundtrip preserves the string identifier json_str = agent_plan.model_dump_json(serialize_as_any=True) diff --git a/python/flink_agents/plan/tests/test_agent_plan_cross_language.py b/python/flink_agents/plan/tests/test_agent_plan_cross_language.py index fbf467116..31bacf532 100644 --- a/python/flink_agents/plan/tests/test_agent_plan_cross_language.py +++ b/python/flink_agents/plan/tests/test_agent_plan_cross_language.py @@ -77,7 +77,7 @@ def test_compile_agent_with_python_function_descriptor() -> None: """ApiPythonFunction added via add_action becomes plan PythonFunction.""" agent = Agent() pf = _make_python_function_descriptor() - agent.add_action(name="act", events=[InputEvent.EVENT_TYPE], func=pf) + agent.add_action(name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=pf) plan = AgentPlan.from_agent(agent, AgentConfiguration()) action = plan.actions["act"] @@ -87,7 +87,7 @@ def test_compile_agent_with_python_function_descriptor() -> None: ) assert action.exec.module == pf.module assert action.exec.qualname == pf.qualname - assert action.listen_event_types == [InputEvent.EVENT_TYPE] + assert action.trigger_conditions== [InputEvent.EVENT_TYPE] def test_compile_agent_with_java_function_descriptor() -> None: @@ -99,7 +99,7 @@ def test_compile_agent_with_java_function_descriptor() -> None: """ agent = Agent() jf = _make_java_function_descriptor() - agent.add_action(name="act", events=[InputEvent.EVENT_TYPE], func=jf) + agent.add_action(name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=jf) plan = AgentPlan.from_agent(agent, AgentConfiguration()) action = plan.actions["act"] @@ -110,7 +110,7 @@ def test_compile_agent_with_java_function_descriptor() -> None: assert action.exec.qualname == jf.qualname assert action.exec.method_name == jf.method_name assert list(action.exec.parameter_types) == list(jf.parameter_types) - assert action.listen_event_types == [InputEvent.EVENT_TYPE] + assert action.trigger_conditions== [InputEvent.EVENT_TYPE] def test_python_plan_compile_does_not_validate_java_class_exists() -> None: @@ -126,7 +126,7 @@ def test_python_plan_compile_does_not_validate_java_class_exists() -> None: method_name="ghost", parameter_types=["java.lang.String", "int"], ) - agent.add_action(name="act", events=[InputEvent.EVENT_TYPE], func=fake) + agent.add_action(name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=fake) plan = AgentPlan.from_agent(agent, AgentConfiguration()) assert plan.actions["act"].exec.qualname == "com.does.not.Exist" @@ -136,7 +136,7 @@ def test_compile_preserves_action_config() -> None: agent = Agent() agent.add_action( name="act", - events=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], func=_make_python_function_descriptor(), timeout_sec=30, retry=2, @@ -155,7 +155,7 @@ class WeirdFunction(ApiFunction): agent = Agent() agent.add_action( - name="act", events=[InputEvent.EVENT_TYPE], func=WeirdFunction() + name="act", trigger_conditions=[InputEvent.EVENT_TYPE], func=WeirdFunction() ) with pytest.raises(TypeError, match="Unsupported function descriptor"): @@ -170,7 +170,7 @@ def _java_action_plan() -> AgentPlan: agent = Agent() agent.add_action( name="handle", - events=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], func=_make_java_function_descriptor(), ) return AgentPlan.from_agent(agent, AgentConfiguration()) @@ -181,7 +181,7 @@ def _python_action_plan() -> AgentPlan: agent = Agent() agent.add_action( name="handle", - events=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], func=_make_python_function_descriptor(), ) return AgentPlan.from_agent(agent, AgentConfiguration()) @@ -305,7 +305,7 @@ def test_python_plan_with_java_action_matches_runtime_operator_wire_shape() -> N agent = Agent() agent.add_action( name="handle", - events=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], func=ApiJavaFunction( qualname=handler_qualname, method_name="handleInput", @@ -318,7 +318,7 @@ def test_python_plan_with_java_action_matches_runtime_operator_wire_shape() -> N handle_block = emitted["actions"]["handle"] assert handle_block["name"] == "handle" - assert handle_block["listen_event_types"] == [InputEvent.EVENT_TYPE] + assert handle_block["trigger_conditions"] == [InputEvent.EVENT_TYPE] assert handle_block["config"] is None assert handle_block["exec"] == { "func_type": "JavaFunction", @@ -340,7 +340,7 @@ def test_python_preserves_conf_data_types_and_event_ordering() -> None: "module": _dummy_action.__module__, "qualname": _dummy_action.__qualname__, }, - "listen_event_types": [InputEvent.EVENT_TYPE], + "trigger_conditions": [InputEvent.EVENT_TYPE], "config": None, }, "second": { @@ -350,7 +350,7 @@ def test_python_preserves_conf_data_types_and_event_ordering() -> None: "module": _dummy_action.__module__, "qualname": _dummy_action.__qualname__, }, - "listen_event_types": [InputEvent.EVENT_TYPE], + "trigger_conditions": [InputEvent.EVENT_TYPE], "config": None, }, }, diff --git a/python/flink_agents/runtime/tests/test_built_in_actions.py b/python/flink_agents/runtime/tests/test_built_in_actions.py index b7eb5a294..057291c15 100644 --- a/python/flink_agents/runtime/tests/test_built_in_actions.py +++ b/python/flink_agents/runtime/tests/test_built_in_actions.py @@ -33,6 +33,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.prompts.prompt import Prompt from flink_agents.api.resource import ResourceDescriptor, ResourceType @@ -171,7 +172,7 @@ def add(a: int, b: int) -> int: """ return a + b - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process_input(event: Event, ctx: RunnerContext) -> None: """User defined action for processing input. @@ -187,7 +188,7 @@ def process_input(event: Event, ctx: RunnerContext) -> None: ) ) - @action(ChatResponseEvent.EVENT_TYPE) + @action(EventType.ChatResponseEvent) @staticmethod def process_chat_response(event: Event, ctx: RunnerContext) -> None: """User defined action for processing chat model response.""" diff --git a/python/flink_agents/runtime/tests/test_get_resource_in_action.py b/python/flink_agents/runtime/tests/test_get_resource_in_action.py index f1f1e8e15..8c5988bb1 100644 --- a/python/flink_agents/runtime/tests/test_get_resource_in_action.py +++ b/python/flink_agents/runtime/tests/test_get_resource_in_action.py @@ -22,6 +22,7 @@ from flink_agents.api.chat_models.chat_model import BaseChatModelSetup from flink_agents.api.decorators import action, chat_model_setup, tool from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.resource import ResourceDescriptor, ResourceType from flink_agents.api.runner_context import RunnerContext @@ -74,7 +75,7 @@ def mock_tool(input: str) -> str: """ return input + " mock tools just for testing." - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def mock_action(event: Event, ctx: RunnerContext) -> None: input = InputEvent.from_event(event).input diff --git a/python/flink_agents/runtime/tests/test_local_execution_environment.py b/python/flink_agents/runtime/tests/test_local_execution_environment.py index 1c861b359..294549d22 100644 --- a/python/flink_agents/runtime/tests/test_local_execution_environment.py +++ b/python/flink_agents/runtime/tests/test_local_execution_environment.py @@ -35,6 +35,7 @@ ) from flink_agents.api.events.chat_event import ChatRequestEvent, ChatResponseEvent from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.resource import ResourceDescriptor, ResourceType from flink_agents.api.runner_context import RunnerContext @@ -42,7 +43,7 @@ class Agent1(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def increment(event: Event, ctx: RunnerContext): # noqa D102 input = InputEvent.from_event(event).input @@ -51,7 +52,7 @@ def increment(event: Event, ctx: RunnerContext): # noqa D102 class Agent1WithAsync(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod async def increment(event: Event, ctx: RunnerContext): # noqa D102 def my_func(value: int) -> int: @@ -64,7 +65,7 @@ def my_func(value: int) -> int: class Agent2(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def decrease(event: Event, ctx: RunnerContext): # noqa D102 input = InputEvent.from_event(event).input @@ -145,7 +146,7 @@ def test_local_execution_environment_call_from_list_twice() -> None: class UnifiedEventAgent(Agent): - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def on_input(event: Event, ctx: RunnerContext) -> None: ctx.send_event( @@ -199,7 +200,7 @@ def data(self) -> str: class MixedEventAgent(Agent): """Agent mixing subclassed and string-based event routing.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def start(event: Event, ctx: RunnerContext) -> None: ctx.send_event(Step1Event(data=str(InputEvent.from_event(event).input))) diff --git a/python/flink_agents/runtime/tests/test_local_runner_cross_language.py b/python/flink_agents/runtime/tests/test_local_runner_cross_language.py index 7075fc714..3e9c0412e 100644 --- a/python/flink_agents/runtime/tests/test_local_runner_cross_language.py +++ b/python/flink_agents/runtime/tests/test_local_runner_cross_language.py @@ -42,7 +42,7 @@ def _make_java_function_descriptor() -> ApiJavaFunction: def test_local_runner_dispatches_python_function_action() -> None: agent = Agent() agent.add_action( - name="echo", events=[InputEvent.EVENT_TYPE], func=echo_action + name="echo", trigger_conditions=[InputEvent.EVENT_TYPE], func=echo_action ) runner = LocalRunner(agent, AgentConfiguration()) @@ -55,7 +55,7 @@ def test_local_runner_dispatch_of_java_function_action_fails_without_jvm_bridge( agent = Agent() agent.add_action( name="handle", - events=[InputEvent.EVENT_TYPE], + trigger_conditions=[InputEvent.EVENT_TYPE], func=_make_java_function_descriptor(), ) diff --git a/python/flink_agents/runtime/tests/test_runner_context_execute.py b/python/flink_agents/runtime/tests/test_runner_context_execute.py index fd2a54733..abde15a63 100644 --- a/python/flink_agents/runtime/tests/test_runner_context_execute.py +++ b/python/flink_agents/runtime/tests/test_runner_context_execute.py @@ -20,6 +20,7 @@ from flink_agents.api.agents.agent import Agent from flink_agents.api.decorators import action from flink_agents.api.events.event import Event, InputEvent, OutputEvent +from flink_agents.api.events.event_type import EventType from flink_agents.api.execution_environment import AgentsExecutionEnvironment from flink_agents.api.runner_context import RunnerContext @@ -42,7 +43,7 @@ def raise_exception(msg: str) -> None: class AgentWithDurableExecute(Agent): """Agent that uses synchronous durable_execute() method.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process(event: Event, ctx: RunnerContext) -> None: """Process an event using durable_execute().""" @@ -54,7 +55,7 @@ def process(event: Event, ctx: RunnerContext) -> None: class AgentWithMultipleDurableExecute(Agent): """Agent that makes multiple durable_execute() calls.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process(event: Event, ctx: RunnerContext) -> None: """Process an event with multiple durable_execute() calls.""" @@ -67,7 +68,7 @@ def process(event: Event, ctx: RunnerContext) -> None: class AgentWithDurableExecuteAndAsync(Agent): """Agent that uses both durable_execute() and durable_execute_async().""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod async def process(event: Event, ctx: RunnerContext) -> None: """Process an event using both durable_execute() and durable_execute_async().""" @@ -82,7 +83,7 @@ async def process(event: Event, ctx: RunnerContext) -> None: class AgentWithDurableExecuteException(Agent): """Agent that uses durable_execute() with a function that raises an exception.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process(event: Event, ctx: RunnerContext) -> None: """Process an event where durable_execute() raises an exception.""" @@ -96,7 +97,7 @@ def process(event: Event, ctx: RunnerContext) -> None: class AgentWithKwargs(Agent): """Agent that uses durable_execute() with keyword arguments.""" - @action(InputEvent.EVENT_TYPE) + @action(EventType.InputEvent) @staticmethod def process(event: Event, ctx: RunnerContext) -> None: """Process an event using durable_execute() with kwargs.""" diff --git a/runtime/src/test/java/org/apache/flink/agents/runtime/RescalingTest.java b/runtime/src/test/java/org/apache/flink/agents/runtime/RescalingTest.java index a829e62d2..bdd5efe1b 100644 --- a/runtime/src/test/java/org/apache/flink/agents/runtime/RescalingTest.java +++ b/runtime/src/test/java/org/apache/flink/agents/runtime/RescalingTest.java @@ -19,6 +19,7 @@ package org.apache.flink.agents.runtime; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -504,14 +505,14 @@ public static class TestAgent extends Agent { public static final AtomicInteger numProcessedEvent = new AtomicInteger(0); - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void handleInputEvent(Event event, RunnerContext context) { InputEvent inputEvent = InputEvent.fromEvent(event); numProcessedEvent.incrementAndGet(); context.sendEvent(new TestEvent((Integer) inputEvent.getInput())); } - @Action(listenEventTypes = {TestEvent.EVENT_TYPE}) + @Action(TestEvent.EVENT_TYPE) public static void handleTestEvent(Event event, RunnerContext context) { TestEvent testEvent = (TestEvent) event; numProcessedEvent.incrementAndGet(); diff --git a/runtime/src/test/java/org/apache/flink/agents/runtime/ResourceCacheTest.java b/runtime/src/test/java/org/apache/flink/agents/runtime/ResourceCacheTest.java index a48f618e5..f17e16d48 100644 --- a/runtime/src/test/java/org/apache/flink/agents/runtime/ResourceCacheTest.java +++ b/runtime/src/test/java/org/apache/flink/agents/runtime/ResourceCacheTest.java @@ -19,6 +19,7 @@ package org.apache.flink.agents.runtime; import org.apache.flink.agents.api.Event; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.agents.Agent; import org.apache.flink.agents.api.annotation.ChatModelSetup; @@ -124,7 +125,7 @@ public static ResourceDescriptor pythonChatModel() { @Tool private TestTool anotherTool = new TestTool("anotherTool"); - @org.apache.flink.agents.api.annotation.Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @org.apache.flink.agents.api.annotation.Action(EventType.InputEvent) public void handleInputEvent(Event event, RunnerContext context) { InputEvent inputEvent = InputEvent.fromEvent(event); } diff --git a/runtime/src/test/java/org/apache/flink/agents/runtime/memory/ShortTermMemoryTTLIntegrationTest.java b/runtime/src/test/java/org/apache/flink/agents/runtime/memory/ShortTermMemoryTTLIntegrationTest.java index 1e9113840..97e4099e2 100644 --- a/runtime/src/test/java/org/apache/flink/agents/runtime/memory/ShortTermMemoryTTLIntegrationTest.java +++ b/runtime/src/test/java/org/apache/flink/agents/runtime/memory/ShortTermMemoryTTLIntegrationTest.java @@ -18,6 +18,7 @@ package org.apache.flink.agents.runtime.memory; import org.apache.flink.agents.api.AgentsExecutionEnvironment; +import org.apache.flink.agents.api.EventType; import org.apache.flink.agents.api.InputEvent; import org.apache.flink.agents.api.OutputEvent; import org.apache.flink.agents.api.agents.Agent; @@ -56,7 +57,7 @@ private TestInput(String eventKey, long sleepMs) { public static class TTLTestAgent extends Agent { - @Action(listenEventTypes = {InputEvent.EVENT_TYPE}) + @Action(EventType.InputEvent) public static void input(org.apache.flink.agents.api.Event event, RunnerContext ctx) throws Exception { InputEvent inputEvent = (InputEvent) event; diff --git a/runtime/src/test/java/org/apache/flink/agents/runtime/operator/CrossLanguageActionRuntimeTest.java b/runtime/src/test/java/org/apache/flink/agents/runtime/operator/CrossLanguageActionRuntimeTest.java index 6d3eedd31..08a09b6e3 100644 --- a/runtime/src/test/java/org/apache/flink/agents/runtime/operator/CrossLanguageActionRuntimeTest.java +++ b/runtime/src/test/java/org/apache/flink/agents/runtime/operator/CrossLanguageActionRuntimeTest.java @@ -118,7 +118,7 @@ private static String pythonShapedPlanJson() { + " \"org.apache.flink.agents.api.context.RunnerContext\"" + " ]" + " }," - + " \"listen_event_types\":[\"_input_event\"]," + + " \"trigger_conditions\":[\"_input_event\"]," + " \"config\":null" + " }" + "},"