Repository navigation
Python: continue declarative workflows after empty conditional branches - #10184
Kip (uragoodman) wants to merge 6 commits into
Conversation
Add a ThenPassthrough continuation node for empty then branches, mirroring the existing ElsePassthrough path, and cover graph wiring and condition routing with regression tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ty-then-continuation
| then_actions = action_def.get("then", action_def.get("actions", [])) | ||
| then_entry = self._create_executors_for_actions(then_actions, builder, branch_context) | ||
| then_passthrough = None | ||
| if then_entry is None: |
There was a problem hiding this comment.
same dead end is still in _create_condition_group_structure: a condition with empty actions matches, the evaluator sends branch_index=i, but nothing listens for it so the next action never runs
if branch_entry:
branch_entries.append((i, branch_entry))
# Track exit for later wiring
branch_exit = self._get_branch_exit(branch_entry)
if branch_exit:
branch_exits.append(branch_exit)
+ else:
+ case_passthrough = JoinExecutor(
+ {"kind": "CasePassthrough"}, id=self._allocate_generated_id(f"{action_id}_case{i}_pass")
+ )
+ self._executors[case_passthrough.id] = case_passthrough
+ branch_entries.append((i, case_passthrough))
+ branch_exits.append(case_passthrough)fixed this plus a test in this commit, you can just cherry pick it instead of redoing it: its-amann@be2f39d
(cherry picked from commit be2f39d)
|
Cherry-picked Aman (@its-amann)'s fix as 92c901c, with author metadata preserved and the test included. The empty ConditionGroup case now gets a CasePassthrough registered in both branch_entries and branch_exits, so the evaluator's branch_index has a listener and the following action runs. Ran the declarative unit suite (pytest -m 'not integration'): passed. Thanks for the fix! |
|
/review |
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: Findings reported
Scope: full PR (3 commit(s)): d8a3eca37429, c1c4fcb13579, 92c901c12c63
Model: gpt-5.6-sol
Overview
The change restores continuation for genuinely empty If and ConditionGroup branches through generated, collision-safe passthrough executors, with focused graph-routing tests and existing generic successor wiring providing strong guardrails. However, the new emptiness checks use executor-construction failure as a proxy for an empty authored branch, so a non-empty branch containing only unsupported actions now falls through to downstream work instead of stopping. This can silently skip a misspelled or unavailable guard action and execute subsequent side effects.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 medium) across 1 file. Details are attached to the affected lines below.
Affected areas: python/packages/declarative/agent_framework_declarative/_workflows/_declarative_builder.py
| then_actions = action_def.get("then", action_def.get("actions", [])) | ||
| then_entry = self._create_executors_for_actions(then_actions, builder, branch_context) | ||
| then_passthrough = None | ||
| if then_entry is None: |
There was a problem hiding this comment.
_create_executors_for_actions() also returns None when a non-empty branch contains only unknown action kinds, because those actions are warned about and skipped. This check (and the equivalent new ConditionGroup fallback) therefore treats a misspelled or unavailable guard action as an empty no-op branch and continues into downstream actions, potentially executing side effects that the branch was meant to gate. Please base both passthrough decisions on whether the authored action list is actually empty, or reject unsupported nested actions instead of continuing.
There was a problem hiding this comment.
Addressed in 50f7854: passthrough creation now keys off whether the authored action list is empty, so a non-empty branch containing only unsupported actions keeps its existing no-continuation behavior. Added regression tests covering both the If and ConditionGroup cases; the declarative suite now reports 1611 passed.
Base the passthrough decision on the authored action list rather than on whether an executor was created. Non-empty branches containing only unsupported actions no longer continue as empty branches. Preserve the existing empty-branch passthroughs and the ConditionGroup fix from @its-amann. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ty-then-continuation
|
Hi Eduard van Valkenburg (@eavanvalkenburg) — thanks for approving and rerunning this head. The rerun still failed with an xdist worker crash rather than a declarative assertion:
The PR touches 3 files under The Could you rerun the failed job once more? I'm also happy to merge latest |
…ty-then-continuation
Motivation & Context
Declarative conditional actions can have empty branches: an
Ifwith nothenactions (
then: [],then: null, orthenomitted with noactionsfallback),and a
ConditionGroupcase with no actions. The builder created continuationpassthroughs for empty
else/default paths but not for these empty casebranches. A matched branch therefore had no outgoing edge for its
ConditionResult.branch_index, so the action after the conditional wasunreachable from that branch in the graph.
This change adds symmetric passthroughs for empty branches:
ThenPassthroughfor an empty
Ifthen branch andCasePassthroughfor an emptyConditionGroupcase. Both provide a continuation node so the following action is reachable from
the matched branch.
The passthrough is added only when the authored branch is empty. A branch whose
actions are all skipped as unsupported is not treated as an empty branch.
This matters because:
then/case branches are valid no-op or guard branches; when matched,downstream responses, state updates, and tool or agent calls must remain
reachable instead of being skipped.
else/default paths.Without this change, the builder still succeeds, but the matched branch has no
continuation edge in the graph, so downstream actions are unreachable on that
branch's graph path.
Description & Review Guide
Ifwhose authoredthenlist is empty (then: [],then: null,or
thenomitted with noactionsfallback), create aThenPassthroughJoinExecutor, wire the evaluator withbranch_index == 0, and use it asthe then-branch exit.
ConditionGroupcase whose authoredactionslist is empty ([],null, or omitted), create aCasePassthroughJoinExecutor, register itin both
branch_entriesandbranch_exits, and wire it to the case'sbranch_index.ElsePassthrough/default handling.empty, rather than on whether executor construction returned an entry. A
non-empty branch containing only unsupported actions therefore keeps its
existing no-continuation behavior.
thenand emptyConditionGroupcase wiring, condition routing, the non-empty
thenpath, and non-emptybranches containing only unsupported actions; update the nullable-then
generated-ID expectation.
ConditionGroupfix cherry-picked from Aman (@its-amann) as92c901c12, with the original author metadata preserved.Ifactions whose authoredthenvalue is empty(
then: [],then: null, orthenomitted with noactionsfallback),and
ConditionGroupcases whose authoredactionslist is empty, change.Non-empty branches keep their existing routing, including branches whose
actions are all skipped as unsupported.
failure, so a branch with only unsupported actions is not silently treated
as an empty branch.
else/default passthrough paths.wiring, since the successor is not known when the structure is built.
ConditionGroupcommit and its attribution.Related Issue
Fixes #10094
The issue is open, has been reproduced by the triage workflow, and has the
ready-for-implementationlabel. I am happy to adjust the approach ifmaintainers prefer. No other open PR references this issue.
The
ConditionGroupcase is the same empty-branch continuation problem and isincluded here rather than as a parallel fix. If maintainers prefer a separate
issue for that part, I can split the cherry-picked commit out.
AI Assistance
AI assistance details: implementation, tests, and PR description were drafted
with an AI coding assistant; I reviewed the diff and ran the focused tests and
static checks locally. The
ConditionGroupfix was authored by Aman (@its-amann) andcherry-picked with the original author metadata preserved.
Contribution Checklist