Conversation
|
Hi @wenjin272, I closed the PR #561 and opened this. Do take a first pass when you get a chance. |
There was a problem hiding this comment.
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
PythonEventin java, unified inEvent - Subclasses of
Eventprovidefrom_eventmethod 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 {}; |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
I think we can remove this field to keep the align between python Event and java Event
There was a problem hiding this comment.
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"] |
There was a problem hiding this comment.
Shall we return self.get_attr("model")?
| attributes={ | ||
| "model": model, | ||
| "messages": messages, | ||
| "output_schema": output_schema, |
There was a problem hiding this comment.
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.
| Key-value properties for the event data. | ||
| """ | ||
|
|
||
| _type_registry: ClassVar[Dict[str, Type["Event"]]] = {} |
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
|
@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. |
…vent() in actions
aff5f51 to
744e498
Compare
|
@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. |
Linked issue: #424
Purpose of change
Add unified event support. Users can create events with a
typestring andattributesmap 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.
Eventclass (Java/Python) gainstype,attributes,getType()/get_type().@Actionannotation gainslistenEventTypes().More details about the design in the issue #424
Documentation
doc-neededdoc-not-neededdoc-included