weiqingy commented on code in PR #977:
URL: https://github.com/apache/flink-agents/pull/977#discussion_r3739205315


##########
docs/content/docs/development/workflow_agent.md:
##########
@@ -264,9 +278,142 @@ public class ReviewAnalysisAgent extends Agent {
 
 {{< /tabs >}}
 
-In the function, user can also send new events, to trigger other actions, or 
output the data.
+### Trigger Condition Syntax
+
+Use `EventType` constants for built-in exact event types. Inside a condition 
expression, compare
+`type` with the constant, for example `type == EventType.InputEvent`. 
`EventType.InputEvent` by
+itself is a value, not a condition.
+
+A bare identifier or dotted path is treated as an exact event type, so check 
an attribute explicitly,
+for example `ready == true` or `attributes.ready == true`. An unquoted value 
that starts with
+`EventType.` is treated as a condition expression. To use such a value as an 
exact event type, quote
+the whole name, for example `'EventType.custom'`.
+
+Custom event types may be bare names such as `order.created` or 
`order-created`. Each dot-separated
+segment must start with an ASCII letter or underscore and may then contain 
ASCII letters, digits,
+underscores, or hyphens. Quote names that contain other punctuation or would 
otherwise be treated as
+condition expressions, for example `'order:created'` or `'true'`. A quoted 
event type must be
+non-empty and cannot contain whitespace, quotes, backslashes, or control 
characters.
+
+### Trigger Condition Examples
+
+Multiple values use OR semantics. Entries may use `EventType` constants, 
event-class
+`EVENT_TYPE` constants, custom event strings, or Boolean expressions:
+
+```java
+@Action({
+        EventType.InputEvent,
+        ChatResponseEvent.EVENT_TYPE,
+        "MyCustomEvent",
+        "attributes.urgent == true"})
+public static void handleAnyTrigger(Event event, RunnerContext ctx) {}
+```
+
+In the example above, an input event matches even when `urgent` is false 
because separate entries
+are OR branches. Put type and attribute checks in one expression when both are 
required:
+
+```java
+@Action("type == EventType.InputEvent && input.score > 5 && input.ip.name == 
'Chinese'")
+public static void handleQualifiedInput(Event event, RunnerContext ctx) {}
+```
+
+Dots and hyphens are valid in a bare exact event type. Quote the event type 
when its name contains
+other punctuation or would otherwise be interpreted as a condition expression:
+
+```java
+@Action("com.example.order.created")
+public static void handleDottedOrderCreated(Event event, RunnerContext ctx) {}
+
+@Action("order-created")
+public static void handleOrderCreated(Event event, RunnerContext ctx) {}
+
+@Action("'order:created'")
+public static void handleColonOrderCreated(Event event, RunnerContext ctx) {}
+```
+
+Actions can also be registered programmatically:
+
+{{< tabs "Programmatic Action" >}}
+
+{{< tab "Python" >}}
+```python
+agent.add_action(
+    "process_event",
+    [
+        EventType.InputEvent,
+        "type == EventType.ChatResponseEvent && response.content != ''",
+    ],
+    process_event,
+)
+```
+{{< /tab >}}
+
+{{< tab "Java" >}}
+```java
+public class ProgrammaticAgent extends Agent {
+    public ProgrammaticAgent() throws NoSuchMethodException {
+        addAction(
+                new String[] {
+                    EventType.InputEvent,
+                    "type == EventType.ChatResponseEvent && response.content 
!= ''"
+                },
+                ProgrammaticAgent.class.getMethod(
+                        "processEvent", Event.class, RunnerContext.class));
+    }
+
+    public static void processEvent(Event event, RunnerContext ctx) {
+        // Handle either matching event.
+    }
+}
+```
+{{< /tab >}}
+
+{{< /tabs >}}
+
+### Condition Data
+
+Condition expressions are written in CEL and evaluated by the Java runtime for 
both Java and Python
+actions. The runtime provides these framework variables:
+
+- `type`: the event type string.
+- `id`: the event ID as a string.
+- `EventType`: the built-in event-type constants.
+- `attributes`: the event's attribute map.
+
+Referenced top-level attributes are also available as bare variables, so 
`score > 80` and
+`attributes.score > 80` refer to the same field. All four framework variables 
take precedence over
+attributes with the same names. Use the `attributes` namespace, such as 
`attributes["type"]` or
+`attributes["id"]`, to access colliding attribute keys.
+
+Nested values are not flattened. For an input event whose attributes are
+`{input: {status: "ok"}}`, use `input.status` or `attributes.input.status`; 
bare `status` is not
+available. Other event payloads keep their top-level envelope, for example 
`response.content`.
+
+Use a literal index for top-level keys containing dots, such as 
`attributes["a.b.c"]`, and test
+static membership with `"a.b.c" in attributes`. Dynamic access at the root, 
such as
+`attributes[key]`, and expressions over the whole `attributes` map are not 
supported. Dynamic access

Review Comment:
   "Not supported" sits in the same register as line 398's "remains absent", 
but this one is a hard failure: `ConditionExpressionCompiler.classifyIdent` 
throws from the `ActionMatcher` constructor, so the job fails at operator 
initialization. The fixture `dynamic_whole_attributes_index` captures the 
split, `plan_validation: pass` with `runtime_compilation: fail`.
   
   Would naming the outcome help a reader tell the two apart? Maybe something 
like "rejected when the runtime compiles the condition, so the job fails to 
start", if that reads right to you.



##########
docs/content/docs/development/yaml.md:
##########
@@ -278,25 +278,78 @@ Inline action (map) fields:
 |-------|----------|-------------|
 | `name` | yes | Action name (unique within the agent). |
 | `function` | yes | Fully-qualified callable in the form 
`<module-or-class>:<qualname>`. See [Function 
references](#function-references). |
-| `trigger_conditions` | yes | List of event types the action listens to. 
Built-in [event aliases](#event-aliases) (`input`, `chat_request`, ...) or your 
own event-type strings. |
+| `trigger_conditions` | yes | Non-empty list of strings containing exact 
event types or condition expressions that return a Boolean. Each string must 
contain at least one non-whitespace character. Built-in [event 
aliases](#event-aliases) (`input`, `chat_request`, ...) may be used as complete 
entries. All entries use OR semantics. |
 | `type` | no | Implementation language: `python` or `java`. Defaults to 
`python` (see [Selecting the implementation 
language](#selecting-the-implementation-language)). |
 | `config` | no | Free-form configuration map passed to the action at runtime. 
|
 
+For built-in exact event types, prefer an alias such as `input`. Custom event 
types may be bare names
+such as `order.created` or `order-created`; each dot-separated segment must 
start with an ASCII
+letter or underscore and may then contain ASCII letters, digits, underscores, 
or hyphens. A bare
+identifier or dotted path is treated as an event type, so Boolean attributes 
need an explicit check
+such as `ready == true` or `attributes.ready == true`.
+
+Inside a condition expression, compare `type` with a built-in constant, for 
example
+`type == EventType.InputEvent`. Do not use `EventType.InputEvent` alone: it is 
a value, not a Boolean
+condition.
+
+Every `trigger_conditions` entry must be a string with at least one 
non-whitespace character. Empty
+or whitespace-only strings are rejected. Quote condition expressions in YAML, 
including literals
+such as `- "true"` and predicates such as `- "ready == true"`; otherwise YAML 
may convert a value
+such as `true`, `false`, or `null` to a non-string value before validation.
+
+Hyphenated event types need no extra quoting layer:
+
+```yaml
+trigger_conditions:
+  - order-created
+```
+
+For event types containing other punctuation, or names such as `true` that 
would otherwise be
+interpreted as condition expressions, wrap the event type itself in quotes. 
YAML removes its own
+scalar quotes, so the quotes used by trigger-condition classification must be 
part of the scalar
+value, for example `- "'order:created'"` or `- "'true'"`. The inner text must 
be non-empty and cannot
+contain whitespace, quotes, backslashes, or control characters.
+
+An unquoted value that starts with `EventType.` is treated as a condition 
expression. To use such a
+value as an exact event type, preserve the single quotes inside the YAML 
string, for example
+`- "'EventType.custom'"`.
+
 ```yaml
 actions:
   - name: action1
     function: my_pkg.actions:action1
-    trigger_conditions: [input]
+    trigger_conditions: [input, custom_event]
     type: python
   - name: action2
     function: my_pkg.actions:action2
-    trigger_conditions: [chat_response]
+    trigger_conditions:
+      - "type == EventType.ChatResponseEvent && response.content != ''"
     type: python
   - action3                       # shared action reference (declared at file 
level)
 ```
 
 Action method signatures are fixed (`(Event, RunnerContext)`), so there is no 
`parameter_types` field on actions.
 
+Different matching actions all run (fan-out), while one action runs at most 
once for an event.
+Separate entries are OR branches. To combine a type restriction with an 
attribute predicate using
+AND, write both checks in one Boolean expression, as shown by `action2` above. 
Exact type matches run
+before matches from condition expressions.
+
+Expressions expose the event type as `type`, built-in constants under 
`EventType`, and the event
+attribute envelope under `attributes`. Referenced top-level entries from 
`Event.attributes` are also
+available directly. Nested values stay under their top-level attribute path 
and are never flattened.
+For an input event whose attributes are `{input: {status: "ok"}}`, both 
`input.status` and
+`attributes.input.status` are valid, while bare `status` is not. Other event 
payloads follow the same

Review Comment:
   "is not" reads as rejected, though nothing rejects bare `status`. It clears 
plan validation and the type check (`ConditionExpressionCompiler.java:124` 
declares non-framework idents `SimpleType.DYN`), then throws unbound at 
evaluation. Under the default `WARN_AND_SKIP` that is logged and treated as 
false, so the action just never fires.
   
   That default lives only in the `configuration.md` row this PR adds, and 
neither page links to it. Would a sentence on the failure semantics plus a link 
fit here, the way `monitoring.md:335` points at `event-log.level`? Same two 
gaps on `workflow_agent.md`, if so.



##########
docs/content/docs/development/yaml.md:
##########
@@ -498,7 +551,7 @@ When `type:` resolves to the **opposite** language of the 
loader, the loader bui
 
 ### Provider aliases
 
-For `clazz:` on resource descriptors and for event names in 
`trigger_conditions:`, you can use a short alias instead of a fully-qualified 
class path.
+For `clazz:` on resource descriptors and for complete event-type entries in 
`trigger_conditions:`, you can use a short alias instead of a fully-qualified 
class path. Event alias replacement is an exact complete-entry lookup: `input` 
is replaced, while `type == input`, `attributes.kind == 'input'`, and the 
quoted event type `'input'` remain unchanged.

Review Comment:
   This sentence now frames the alias table below as the menu of legal 
`trigger_conditions` values, and that table offers `output`. An action 
triggered on `output` never runs: `ActionExecutionOperator.java:247` sends 
OutputEvents downstream in the `if` branch, so the `getActionsTriggeredBy` call 
in the `else` at `:269` is never reached. Nothing fails and nothing logs.
   
   You document exactly this at `workflow_agent.md:472-474`. Should the caveat 
follow the alias table here, or hang off the pointer at 350-351?



-- 
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]

Reply via email to