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

wenjin272 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new d30267af [Doc] Update Custom Event Definition Documentation (#651)
d30267af is described below

commit d30267af044c117847c7650ac6f1debf18d818ec
Author: Adesh Nalpet Adimurthy <[email protected]>
AuthorDate: Sun May 10 22:18:44 2026 -0400

    [Doc] Update Custom Event Definition Documentation (#651)
---
 docs/content/docs/development/workflow_agent.md | 102 +++++++++++++++++++++---
 1 file changed, 92 insertions(+), 10 deletions(-)

diff --git a/docs/content/docs/development/workflow_agent.md 
b/docs/content/docs/development/workflow_agent.md
index 5b3da32f..f122727f 100644
--- a/docs/content/docs/development/workflow_agent.md
+++ b/docs/content/docs/development/workflow_agent.md
@@ -491,37 +491,119 @@ To use async execution on JDK 21+, user should append 
jvm option `--add-exports=
 {{< /tabs >}}
 
 ## Event
-Events are messages passed between actions. Events may carry payloads. A 
single event may trigger multiple actions if they are all listening to its type.
 
-There are 2 special types of event.
-* `InputEvent`: Generated by the framework, carrying an input data record that 
arrives at the agent in `input` field . Actions listening to the `InputEvent` 
will be the entry points of agent.
-* `OutputEvent`: The framework will listen to `OutputEvent`, and convert its 
payload in `output` field into outputs of the agent. By generating 
`OutputEvent`, actions can emit output data.
+Events are JSON-serializable messages passed between actions. Every event has 
a `type` string used for routing and an `attributes` map that carries the 
payload. A single event may trigger multiple actions if they are all listening 
to its type.
 
-User can define own event by extends `Event`.
+### Special Events
+
+* `InputEvent`: Generated by the framework, carrying an input data record that 
arrives at the agent in its `input` attribute. Actions listening to 
`InputEvent` are the entry points of the agent.
+* `OutputEvent`: The framework listens to `OutputEvent` and converts its 
`output` attribute into outputs of the agent.
+
+### Unified Event
+
+For simple cases, users can pass data between actions directly using `Event` 
with a custom `type` and `attributes`, without needing to define a subclass. 
For more structured events, see [Custom Event 
Subclasses](#custom-event-subclasses) below.
+
+{{< tabs "Unified Event" >}}
+
+{{< tab "Python" >}}
+```python
+# Send a unified event from one action
+@action(InputEvent.EVENT_TYPE)
+@staticmethod
+def create_my_event(event: Event, ctx: RunnerContext) -> None:
+    ctx.send_event(
+        Event(type="my_event", attributes={"field1": "test", "field2": 42})
+    )
+
+# Consume it in another action
+@action("my_event")
+@staticmethod
+def handle_my_event(event: Event, ctx: RunnerContext) -> None:
+    field1: str = event.get_attr("field1")
+    field2: int = event.get_attr("field2")
+```
+{{< /tab >}}
+
+{{< tab "Java" >}}
+```java
+// Send a unified event from one action
+@Action(listenEventTypes = {InputEvent.EVENT_TYPE})
+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"})
+public static void handleMyEvent(Event event, RunnerContext ctx) {
+    String field1 = (String) event.getAttr("field1");
+    int field2 = (int) event.getAttr("field2");
+}
+```
+{{< /tab >}}
+
+{{< /tabs >}}
+
+### JSON Serialization
+
+Events are serialized as JSON when passed between Python actions or across the 
Java-Python boundary. This means attribute values of non-trivial types (such as 
Pydantic models) lose their type information and arrive as plain `dict` 
objects. Users must manually reconstruct the typed object:
+
+```python
+input_event = InputEvent.from_event(event)
+input_data = ItemData.model_validate(input_event.input)
+```
+
+### Custom Event Subclasses
+
+Users can also define custom event subclasses for reusable, structured events. 
Data should be stored in the `attributes` map, and the subclass must implement 
a `from_event` / `fromEvent` factory method that validates required attributes 
and reconstructs typed objects from the deserialized data.
 
 {{< tabs "Custom Event" >}}
 
 {{< tab "Python" >}}
 ```python
 class MyEvent(Event):
-    value: Any
+    EVENT_TYPE: ClassVar[str] = "my_event"
+
+    def __init__(self, value: str) -> None:
+        super().__init__(type=MyEvent.EVENT_TYPE, attributes={"value": value})
+
+    @classmethod
+    @override
+    def from_event(cls, event: Event) -> "MyEvent":
+        assert "value" in event.attributes
+        return MyEvent(value=event.attributes["value"])
+
+    @property
+    def value(self) -> str:
+        return self.get_attr("value")
 ```
 {{< /tab >}}
 
 {{< tab "Java" >}}
 ```java
 public class MyEvent extends Event {
-    private Object value;
+    public static final String EVENT_TYPE = "my_event";
+
+    public MyEvent(String value) {
+        super(EVENT_TYPE);
+        setAttr("value", value);
+    }
+
+    public static MyEvent fromEvent(Event event) {
+        MyEvent result = new MyEvent((String) event.getAttr("value"));
+        return result;
+    }
+
+    public String getValue() {
+        return (String) getAttr("value");
+    }
 }
 ```
 {{< /tab >}}
 
 {{< /tabs >}}
 
-Then, user can define actions listen to or send `MyEvent`.
-
 {{< hint info >}}
-The payload of python `Event` should be `BaseModel` serializable, of java 
`Event` should be json serializable.
+All attribute values must be JSON-serializable. In Python, this means 
`BaseModel`-serializable or primitive types. In Java, values must be 
Jackson-serializable.
 {{< /hint >}}
 
 ## Built-in Events and Actions

Reply via email to