Repository navigation
Description
Summary
InputMessageNode is a useful HITL gate for collecting user input mid-flow, but it has no node-level guard or pre-execution condition. To skip the prompt when required values are already present in flow state, the only available pattern is a BranchingNode with a 3-step predicate chain: PluginRegexNode (in list mode for empty-detection) → PluginTemplateNode (collapsing to "present" / "missing") → BranchingNode (mapping {"present": "skip"} to a label that bypasses the InputMessageNode).
This works, but is verbose: every skippable HITL gate requires four extra nodes plus the wiring edges. For flows with multiple optional HITL gates this multiplies into noise that obscures the actual control flow.
Reproduction (current pattern, abbreviated)
{
"child_agent_a-uuid_match": { "component_type": "PluginRegexNode", "regex_pattern": "^[0-9a-fA-F]{8}-…$", "return_first_match_only": false },
"child_agent_a-predicate": { "component_type": "PluginTemplateNode", "template": "{{ value | length }}" },
"child_agent_a-check_inputs": { "component_type": "BranchingNode", "branch_name_mapping": { "present": "skip" } },
"child_agent_a-data_gate": { "component_type": "InputMessageNode", "...": "..." },
"child_agent_a-generate": { "component_type": "ApiNode", "...": "..." }
}…plus six edges to wire the four-node predicate chain into the existing data_gate → generate flow.
Feature request
Add an optional guard (or skip_when) field on InputMessageNode that accepts a JSON-pointer / Jinja predicate against flow state. When the predicate evaluates to true, the runtime skips the node without raising, and downstream DataFlowEdges resolve from existing flow state.
{
"child_agent_a-data_gate": {
"component_type": "InputMessageNode",
"guard": {
"kind": "all_present",
"inputs": ["dataRefA", "dataRefB"]
}
}
}This collapses 4 nodes + 6 edges into 1 node + 0 extra edges per skippable gate, dramatically improving flow readability.
Suggested implementation
InputMessageNode.execute() checks self.guard first; if the predicate is truthy against the conversation's input state, the executor returns immediately with no UserMessageRequestStatus — proceeding to whichever node the existing control flow edges target next.
The predicate language can start minimal: { "kind": "all_present", "inputs": [name, ...] } and { "kind": "any_present", "inputs": [name, ...] }. Jinja support can come later.
Related
Distinct from #145 (input-required propagation across A2A boundary) — that concerns runtime state communication. This issue concerns declaring an inline guard predicate so the runtime can skip the prompt entirely without a separate BranchingNode chain.
Environment
wayflowcore[a2a]==26.1.1- Python 3.11
Activity
groganz commentedon May 11, 2026
Cross-linking #160 — another angle on the same theme of richer node-level lifecycle on
InputMessageNode. This issue (#147) wants declarative skip-when-state-satisfied; #160 wants pause-on-external-event.Both push toward
InputMessageNode(or a related node type) growing first-class lifecycle hooks rather than the current binary "always prompt, always wait" contract. Worth considering whether a single richer lifecycle abstraction could subsume both, or whether they should remain separate fields (guard/skip_whenfor #147, external-event pause for #160).Spec-level companion at oracle/agent-spec#182 (no Wait/Schedule primitive in OAS 26.1.0).