Skip to content

[Tech Debt][API][Action] Improve annotation-based cross-language Action declarations #1085

Description

@wenjin272

Search before asking

  • I searched in the issues and found nothing similar.

Description

This is a child issue of #1055. Cross-language Action execution was introduced under #622; this issue reviews the usability of its public declaration API.

Current API

A Java Agent can dispatch an Action to Python by attaching a nested PythonFunction annotation to an annotated Java method:

@Action(
        value = EventType.InputEvent,
        target =
                @PythonFunction(
                        module = "my_pkg.handlers",
                        qualname = "handle_input"))
public static void handle(Event event, RunnerContext ctx) {
    throw new UnsupportedOperationException("cross-language stub");
}

The annotated Java method is not executed. It serves only as the declaration anchor and supplies the Action name, while the Python function is the actual executable target.

The Python decorator API has a similar form when dispatching to Java: a decorated Python function is required even though its body is only a placeholder.

Problems

  • @Action has two different meanings: for native Actions the annotated method is the implementation, while for cross-language Actions the method must never be invoked.
  • Users must write a valid-looking method/function whose only purpose is to fail if called directly.
  • The placeholder signature does not validate the real cross-language target. In particular, the Java plan-layer PythonFunction.checkSignature() is a no-op, so target signature errors are still discovered by the Python runtime.
  • Java exposes two different public types named PythonFunction: api.annotation.PythonFunction and the data descriptor api.function.PythonFunction. Both carry module and qualname, but cannot be reused interchangeably.
  • Action identity is split between the placeholder member name and the target function's qualified name, which makes declarations and diagnostics harder to understand.
  • Annotation/decorator-based registration and programmatic addAction/add_action registration provide overlapping ways to create the same plan, but have different shapes and capabilities.

Design goals

  • Preserve annotation-based Action declarations as a first-class API style.
  • Make the annotated element represent the actual Action implementation or executable descriptor.
  • Avoid requiring a throwing or no-op placeholder body for cross-language Actions.
  • Keep native and cross-language Action declarations easy to distinguish and explain.
  • Reuse a single function-descriptor model where practical.
  • Keep Java, Python, and YAML semantically aligned around Action name, trigger conditions, executable function, and configuration.
  • Validate malformed declarations and unresolved/incompatible targets as early as the relevant runtime boundary permits.

Proposal for discussion: annotate a function-descriptor field

Important

The following is only a proposal for discussion, not an accepted API decision. This issue is intended to compare annotation-based alternatives and agree on the public API before implementation.

One possible design is to allow @Action on both methods and fields:

public class MyAgent extends Agent {

    // The annotated method is the native Java implementation.
    @Action(EventType.InputEvent)
    public static void processLocally(Event event, RunnerContext ctx) {
        // Java Action implementation
    }

    // The annotated field contains the actual cross-language target descriptor.
    @Action(EventType.InputEvent)
    private static final PythonFunction handle =
            PythonFunction.of("my_pkg.handlers", "handle_input");
}

Under this proposal:

  • @Action on a method requires a static Java Action with the (Event, RunnerContext) signature and produces a JavaFunction descriptor.
  • @Action on a field requires a static final field whose value is an API-layer Function descriptor.
  • The method or field name is the default Action name; an optional annotation attribute could override it if needed.
  • Invalid member kinds, null descriptors, duplicate Action names, and invalid native signatures fail during plan construction.
  • The existing API-layer PythonFunction data descriptor is reused, so a separate nested annotation type with the same name is unnecessary.

Other annotation-preserving designs should also be evaluated, for example a repeatable class-level annotation or a dedicated cross-language Action annotation. The final choice should be based on the design goals above rather than assumed by this proposal.

Scope

  • Review the Java @Action(target = @PythonFunction(...)) API and the corresponding Python decorator form.
  • Define the intended relationship between annotation/decorator declarations, function descriptors, and programmatic Action registration.
  • Agree on an annotation-preserving declaration model for cross-language Actions.
  • Define plan-construction and runtime validation behavior.
  • Update Java/Python plan compilation, serialization snapshots, cross-language runtime tests, examples, and documentation after the design is agreed.

Compatibility and migration mechanics are outside the scope of this issue.

Acceptance criteria

  • Annotation-based Action declaration remains supported and documented as a first-class style.
  • A cross-language Action does not require an unused method/function body that throws or does nothing.
  • Native annotated methods continue to clearly represent executable native implementations.
  • Cross-language target descriptors have one unambiguous public representation per language.
  • Action name, trigger conditions, target, and validation behavior are semantically aligned across Java, Python, and YAML.
  • Invalid declarations fail with actionable errors before processing user records where possible.
  • Plan serialization and Java-to-Python/Python-to-Java integration tests cover the agreed design.
  • The final API decision and rationale are recorded in this issue before implementation.

Are you willing to submit a PR?

  • I'm willing to submit a PR!

Activity

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

Metadata

Metadata

Assignees

Labels

fixVersion/0.4.0priority/majorDefault priority of the PR or issue.tech debt[Issue Type] User-unaware issues, such as code refactor and infrastructure maintenance.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions