yunfengzhou-hub commented on issue #1085:
URL: https://github.com/apache/flink-agents/issues/1085#issuecomment-5726488837
Hi @wenjin272, +1 for the proposed direction.
### Proposed changes on top of the issue
One refinement on the Python side: apply the decorator directly to the
descriptor attribute, instead of a placeholder def with `target=`. Today's
placeholder form carries exactly the problems the issue lists for the Java stub
— a body that must never be called, the Action identity split between the
placeholder name and the target qualname, and a placeholder signature that
validates nothing about the real target:
```python
class MyAgent(Agent):
# The decorated attribute is the cross-language target descriptor.
handle = action(EventType.InputEvent)(
JavaFunction.for_action("com.example.Handlers", "handle"))
```
The attribute name is the default Action name, with the issue's optional
`name` override still available. On the form itself: Python's `@` syntax can
only decorate a `def`/`class`, never an assignment, so keeping the literal
`@action` spelling would require a placeholder def — the very thing the design
goals rule out. And `action(...)(descriptor)` is exactly what `@` desugars to
(`f = decorator(f)`); it is the decorator mechanism applied to the descriptor
instead of a placeholder body. Java keeps the literal annotation because
annotations can sit on fields; Python has no `@`-on-assignment, so the two
forms are as close to parity as the languages allow.
The YAML API does not change. YAML is already descriptor-first — name,
trigger conditions, and a language-tagged function reference
(`<module-or-class>:<qualname>`, `type` defaulting to python), with no
placeholder concept — and both loaders accept both action languages, so all
four host/action combinations already work today (examples in the next
section). The plan JSON `exec` block already carries the language-tagged
descriptor (`func_type: PythonFunction | JavaFunction`), so everything above is
declaration-side only: no new keys, no wire or plan-schema change, and
cross-language plan snapshots should stay stable.
### The resulting declaration experience
With the issue's field form plus the Python refinement, declarations read
the same way in both languages — the annotated/decorated element is always
either the native implementation or the executable descriptor.
Java Agent:
```java
public class MyAgent extends Agent {
// Native Action: the annotated method is the implementation.
@Action(EventType.InputEvent)
public static void processLocally(Event event, RunnerContext ctx) {
// Java Action implementation
}
// Cross-language Action: the annotated field is the target descriptor.
@Action(EventType.InputEvent)
private static final PythonFunction handle =
PythonFunction.of("my_pkg.handlers", "handle_input");
}
```
Python Agent:
```python
class MyAgent(Agent):
# Native Action: the decorated method is the implementation.
@action(EventType.InputEvent)
@staticmethod
def process_locally(event: Event, ctx: RunnerContext) -> None:
# Python Action implementation
...
# Cross-language Action: the decorated attribute is the target
descriptor.
handle = action(EventType.InputEvent)(
JavaFunction.for_action("com.example.Handlers", "handle"))
```
YAML keeps its existing syntax in all four host/action combinations:
```yaml
# Java-hosted agent, Java action — e.g.
examples/yaml_review_analysis_agent.yaml
actions:
- name: processInput
type: java
function:
org.apache.flink.agents.examples.agents.ReviewAnalysisAgent:processInput
trigger_conditions: [input]
```
```yaml
# Java-hosted agent, Python action (type omitted)
actions:
- name: handle_input
function: my_pkg.handlers:handle_input
trigger_conditions: [input]
```
```yaml
# Python-hosted agent, Python action (type omitted)
actions:
- name: process_input
function:
flink_agents.e2e_tests.e2e_tests_integration.yaml_test_actions:process_input
trigger_conditions: [input]
```
```yaml
# Python-hosted agent, Java action — e.g.
e2e_tests/resources/yaml_cross_language_java_action.yaml
actions:
- name: multiply_by_two
type: java
function:
org.apache.flink.agents.resource.test.JavaActionHandler:multiplyByTwo
trigger_conditions: [input]
```
Validation: at plan construction, in both languages, invalid member kinds,
null descriptors, and duplicate Action names fail with actionable errors.
Cross-language targets resolve at the earliest boundary that can observe the
real implementation: `JavaFunction` targets when the plan is materialized on
the Java side — for Python-driven jobs, client-side job-graph construction, so
unresolved classes or mismatched signatures fail before submission;
`PythonFunction` targets when the Python worker imports the module and runs
`check_signature` at startup, before any record is processed.
### Migration
0.4 is the designated breaking window, so it might be better to remove
`@Action(target = @PythonFunction(...))` and the decorator `target=` form
outright, with migration notes in the release docs, rather than a deprecation
cycle. @wenjin272 what do you think?
---
Besides, after we reached an agreement on the design, I'm willing to submit
a PR for this issue.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]