Skip to content

Cross Language Unified Event#631

Open
addu390 wants to merge 26 commits intoapache:mainfrom
addu390:feature/custom-event-def-v3
Open

Cross Language Unified Event#631
addu390 wants to merge 26 commits intoapache:mainfrom
addu390:feature/custom-event-def-v3

Conversation

@addu390
Copy link
Copy Markdown
Contributor

@addu390 addu390 commented Apr 15, 2026

Linked issue: #424

Purpose of change

Add unified event support. Users can create events with a type string and attributes map instead of defining subclasses. Enables string-based event routing and JSON-based cross-language transport. Migrates/removes backward compatible with existing subclassed events.

Tests

New unit tests in Java (EventTest, EventLogRecordJsonSerdeTest) and Python (test_event, test_decorators, test_agent_plan, test_local_execution_environment) covering unified event creation, serialization, routing, and backward compatibility.

API

Yes. Event class (Java/Python) gains type, attributes, getType()/get_type(). @Action annotation gains listenEventTypes().

More details about the design in the issue #424

Documentation

  • doc-needed
  • doc-not-needed
  • doc-included

@github-actions github-actions bot added doc-needed Your PR changes impact docs. fixVersion/0.3.0 The feature or bug should be implemented/fixed in the 0.3.0 version. priority/major Default priority of the PR or issue. labels Apr 15, 2026
@addu390 addu390 changed the title Feature/custom event def v3 Cross Language Unified Event Apr 15, 2026
@github-actions github-actions bot added doc-needed Your PR changes impact docs. and removed doc-needed Your PR changes impact docs. labels Apr 15, 2026
@addu390 addu390 marked this pull request as ready for review April 16, 2026 00:24
@addu390
Copy link
Copy Markdown
Contributor Author

addu390 commented Apr 16, 2026

Hi @wenjin272, I closed the PR #561 and opened this.
I'll clean-up the PR a bit more, but up for a review otherwise.

Do take a first pass when you get a chance.

Copy link
Copy Markdown
Collaborator

@wenjin272 wenjin272 left a comment

Choose a reason for hiding this comment

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

Hi, @addu390, thanks for you work. Refactoring the Event will have a significant impact on the framework; therefore, this work requires careful design and attention to numerous details. Thanks Again.

I think though some details still need to be addressed, the current Python event design aligns with my expectations, including

  • action listen to event.type
  • json based DeSer
  • remove PythonEvent in java, unified in Event
  • Subclasses of Event provide from_event method to validate and reconstruct specific event object.

However, the Java event design does not appear to be aligned with the Python approach. In fact, after completing the Event refactoring, we will continue to support cross-language usage of Actions. This means a Python event sent by a Python action may be delivered to a Java action. Therefore, Python events and Java events must maintain consistency in both design and usage.

By the way, there are some conflicts between the PR and the main branch, likely because the main branch was recently reformatted.

* @return Array of Event classes that this action listens to
*/
Class<? extends Event>[] listenEvents();
Class<? extends Event>[] listenEvents() default {};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

On the Python side, actions only support listening to event string identifiers; on the Java side, we should align with this behavior.

* @param eventJson JSON string with at least a {@code "type"} field
* @throws IOException if JSON parsing fails
*/
public void sendUnifiedEvent(String eventJson) throws IOException {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think the name sendUnifiedEvent is a bit ambiguous. I suggest renaming it to sendEventJson or sentPythonEvent.

/** Returns the event type string used for routing. */
@JsonIgnore
public String getType() {
return type != null ? type : this.getClass().getName();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we can directly require that the type is not null, which would simplify the implementation of Event.

private final String type;
private final Map<String, Object> attributes;
/** The timestamp of the source record. */
private Long sourceTimestamp;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we can remove this field to keep the align between python Event and java Event

Copy link
Copy Markdown
Contributor Author

@addu390 addu390 Apr 17, 2026

Choose a reason for hiding this comment

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

sourceTimestamp seems to be used in runtime for timestamp propagation (ActionExecutionOperator, RunnerContextImpl, JavaActionTask, etc.). Safe to remove?

I could however, specifically not use in the cross-language event contract, without any repercussions.

@property
def model(self) -> str:
"""Return the chat model name."""
return self.attributes["model"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Shall we return self.get_attr("model")?

attributes={
"model": model,
"messages": messages,
"output_schema": output_schema,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We need to ensure consistency between the built-in events on the Python and Java sides, so we must make the same changes on the Java side.

Comment thread python/flink_agents/api/events/event.py Outdated
Key-value properties for the event data.
"""

_type_registry: ClassVar[Dict[str, Type["Event"]]] = {}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It appears that this variable is intended to handle the deserialization of subclasses, but it is not currently in use. I think the Event class doesn't need to handle this; deserialization of subclass objects can be managed within the subclass's from_event method. Because subclasses may have certain non-trivial fields that require special handling during deserialization.


def test_action_decorator() -> None: # noqa D103
@action(InputEvent)
@action("_input_event")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we can use InputEvent.EVENT_TYPE, and the same applies to other places where @action is used.

err_msg = (
"Failed to send event '"
+ event.get_type()
+ "' to runner context"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we can also add the event json in err_msg.

event = Event.from_json(event_json)
event_class = Event._type_registry.get(event.type)
if event_class is not None and hasattr(event_class, "from_event"):
return event_class.from_event(event)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Similar to my comment in Event, the framework does not need to be aware of the subclass types of Event. This would require the framework to handle many details of serialization and deserialization.
Fro subclass types of Event, user need use SubClass.from_event() to reconstruct the specific event object in action, like what you do in built-in tool call action and chat action.

@addu390
Copy link
Copy Markdown
Contributor Author

addu390 commented Apr 17, 2026

@wenjin272 Agreed on consistency between Java and Python, the reasoning was that it was quite a larger change, so, was considering having a follow-up PR.
However, It's a fair call-out, let me actually just do that too in this PR, doing so covers most of the review comments too.

@addu390 addu390 force-pushed the feature/custom-event-def-v3 branch from aff5f51 to 744e498 Compare April 17, 2026 23:51
@addu390 addu390 requested a review from wenjin272 April 19, 2026 19:29
@addu390
Copy link
Copy Markdown
Contributor Author

addu390 commented Apr 19, 2026

@wenjin272 Thanks again for the review! I’ve addressed the broader concern of consistency between Python and Java implementations, along side other review comments. Please take another look.

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

Labels

doc-needed Your PR changes impact docs. fixVersion/0.3.0 The feature or bug should be implemented/fixed in the 0.3.0 version. priority/major Default priority of the PR or issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants