Skip to content

fix(workflow): select nested workflow output by terminal node, not arrival order#1013

Open
wolo-lab wants to merge 1 commit into
v2from
wolo/fix-nested-terminal-output
Open

fix(workflow): select nested workflow output by terminal node, not arrival order#1013
wolo-lab wants to merge 1 commit into
v2from
wolo/fix-nested-terminal-output

Conversation

@wolo-lab

Copy link
Copy Markdown

Problem

WorkflowNode surfaced a nested workflow's result as "the last yielded
event with non-nil Output" — which is iteration-order dependent. This
diverged from adk-python and was wrong for two common shapes:

  • Fan-out with multiple terminals: whichever terminal finished last
    by wall-clock won, so the result was non-deterministic across runs.
  • Silent terminal: if the terminal node produced no output but an
    earlier node did, the intermediate node's output was returned as if it
    were the workflow's result.
    The existing linear tests passed only because the single terminal happens
    to emit last (TestNestedWorkflow_MultipleOutputs, despite its name, is
    a linear Chain).

Solution

Select the output from the workflow's terminal node(s) — nodes with
no outgoing edges — computed from graph topology rather than event
arrival order, mirroring adk-python's _set_ctx_output_or_interrupts:

  • exactly one terminal output → forward it;
  • more than one distinct terminal produced output → ErrMultipleOutputs
    (a workflow must have a single output identity; use a JoinNode to
    merge branches);
  • zero → no output.
    Outputs are keyed by terminal node name (last write wins), matching
    adk-python's node_outputs dict, so re-activating a single terminal
    counts as one output rather than an error. Terminal output is read via
    childEventOutput, so a terminal that carries its result as model text
    (MessageAsOutput) is handled too.

A new graph.terminalNodeNames() helper computes the terminal set
(mirrors adk-python's graph._terminal_node_names).

@wolo-lab wolo-lab changed the base branch from main to v2 June 12, 2026 17:46
…rival order

WorkflowNode surfaced a nested workflow's result as "the last yielded
event with non-nil Output", which is iteration-order dependent. This
diverged from adk-python and was wrong for two shapes: a fan-out with
multiple terminals picked a nondeterministic winner, and a silent
terminal returned an earlier node's output as if it were the result.

Select the output from the workflow's terminal node(s) (nodes with no
outgoing edges) by graph topology, mirroring adk-python's
_set_ctx_output_or_interrupts: exactly one terminal output is forwarded,
more than one distinct terminal with output is ErrMultipleOutputs, and
zero means no output. Outputs are keyed by terminal node name (last write
wins, like adk-python's node_outputs dict) so re-activating one terminal
is a single output. Terminal output is read via childEventOutput, so a
MessageAsOutput terminal is handled too.
@wolo-lab wolo-lab force-pushed the wolo/fix-nested-terminal-output branch from 66a4db6 to d14996c Compare June 12, 2026 17:55
@wolo-lab wolo-lab marked this pull request as ready for review June 12, 2026 17:56
@wolo-lab wolo-lab requested a review from hanorik June 12, 2026 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant