Skip to content

feat(workflow): derive node output from message via NodeInfo.MessageAsOutput#966

Merged
wolo-lab merged 3 commits into
v2from
wolo/message-as-output
Jun 9, 2026
Merged

feat(workflow): derive node output from message via NodeInfo.MessageAsOutput#966
wolo-lab merged 3 commits into
v2from
wolo/message-as-output

Conversation

@wolo-lab

@wolo-lab wolo-lab commented Jun 5, 2026

Copy link
Copy Markdown

Problem
A workflow node's output normally lives in Event.Output. But an
LlmAgent node in chat mode emits its answer as message content with no
separate Output value — so anything consuming that node's output (a
successor on a handoff, or a WithUseAsOutput delegation) would see no
output. adk-python solves this with node_info.message_as_output;
adk-go had no equivalent.

Solution
Add NodeInfo.MessageAsOutput. When set and Event.Output is nil,
readers derive the node's output from the event's model text. This mirrors
adk-python's _track_event_in_context (explicit Output wins; message
text is the fallback).

@wolo-lab wolo-lab force-pushed the wolo/message-as-output branch 3 times, most recently from e825441 to 13a85af Compare June 5, 2026 15:28
wolo-lab added a commit that referenced this pull request Jun 5, 2026
…ution

Add NodeInfo.OutputFor: the node paths an event's Output counts for —
the emitter plus any WithUseAsOutput delegating ancestors. A delegating
child's single event is stamped OutputFor=[child, parent, ...] and flows
up, and the parent no longer re-emits a duplicate terminal output event
(full suppression, matching adk-python's _output_delegated + output_for).
Resume attributes a descendant's output to its delegating ancestors via
OutputFor. Every output event records OutputFor (own path minimum),
mirroring adk-python _enrich_event.

Built on the temp integration branch (#960 + #920 + #966); rebase onto v2
once those merge.
@wolo-lab wolo-lab force-pushed the wolo/run_node_use_as_output branch from 3f8bec4 to 843dfca Compare June 5, 2026 20:04
@wolo-lab wolo-lab force-pushed the wolo/message-as-output branch from 13a85af to 749072a Compare June 5, 2026 20:04
wolo-lab added a commit that referenced this pull request Jun 5, 2026
…ution

Add NodeInfo.OutputFor: the node paths an event's Output counts for —
the emitter plus any WithUseAsOutput delegating ancestors. A delegating
child's single event is stamped OutputFor=[child, parent, ...] and flows
up, and the parent no longer re-emits a duplicate terminal output event
(full suppression, matching adk-python's _output_delegated + output_for).
Resume attributes a descendant's output to its delegating ancestors via
OutputFor. Every output event records OutputFor (own path minimum),
mirroring adk-python _enrich_event.

Built on the temp integration branch (#960 + #920 + #966); rebase onto v2
once those merge.
@wolo-lab wolo-lab changed the title feat(workflow): derive node output from message via NodeInfo.MessageA… feat(workflow): derive node output from message via NodeInfo.MessageAsOutput Jun 5, 2026
@wolo-lab wolo-lab marked this pull request as ready for review June 5, 2026 20:25
@wolo-lab wolo-lab requested a review from dpasiukevich June 5, 2026 20:26
@wolo-lab wolo-lab force-pushed the wolo/run_node_use_as_output branch from 843dfca to 94e6366 Compare June 8, 2026 08:04
@wolo-lab wolo-lab force-pushed the wolo/message-as-output branch from 749072a to b0d4a1b Compare June 8, 2026 08:05
wolo-lab added a commit that referenced this pull request Jun 8, 2026
…ution

Add NodeInfo.OutputFor: the node paths an event's Output counts for —
the emitter plus any WithUseAsOutput delegating ancestors. A delegating
child's single event is stamped OutputFor=[child, parent, ...] and flows
up, and the parent no longer re-emits a duplicate terminal output event
(full suppression, matching adk-python's _output_delegated + output_for).
Resume attributes a descendant's output to its delegating ancestors via
OutputFor. Every output event records OutputFor (own path minimum),
mirroring adk-python _enrich_event.

Built on the temp integration branch (#960 + #920 + #966); rebase onto v2
once those merge.
@wolo-lab wolo-lab force-pushed the wolo/run_node_use_as_output branch from 94e6366 to 558781b Compare June 8, 2026 08:16
@wolo-lab wolo-lab force-pushed the wolo/message-as-output branch from b0d4a1b to ba7d347 Compare June 8, 2026 08:16
wolo-lab added a commit that referenced this pull request Jun 8, 2026
…ution

Add NodeInfo.OutputFor: the node paths an event's Output counts for —
the emitter plus any WithUseAsOutput delegating ancestors. A delegating
child's single event is stamped OutputFor=[child, parent, ...] and flows
up, and the parent no longer re-emits a duplicate terminal output event
(full suppression, matching adk-python's _output_delegated + output_for).
Resume attributes a descendant's output to its delegating ancestors via
OutputFor. Every output event records OutputFor (own path minimum),
mirroring adk-python _enrich_event.

Built on the temp integration branch (#960 + #920 + #966); rebase onto v2
once those merge.
wolo-lab added a commit that referenced this pull request Jun 8, 2026
…ution

Add NodeInfo.OutputFor: the node paths an event's Output counts for —
the emitter plus any WithUseAsOutput delegating ancestors. A delegating
child's single event is stamped OutputFor=[child, parent, ...] and flows
up, and the parent no longer re-emits a duplicate terminal output event
(full suppression, matching adk-python's _output_delegated + output_for).
Resume attributes a descendant's output to its delegating ancestors via
OutputFor. Every output event records OutputFor (own path minimum),
mirroring adk-python _enrich_event.

Built on the temp integration branch (#960 + #920 + #966); rebase onto v2
once those merge.
@wolo-lab wolo-lab force-pushed the wolo/message-as-output branch from ba7d347 to 6024efc Compare June 8, 2026 08:17
wolo-lab added a commit that referenced this pull request Jun 8, 2026
…ution

Add NodeInfo.OutputFor: the node paths an event's Output counts for —
the emitter plus any WithUseAsOutput delegating ancestors. A delegating
child's single event is stamped OutputFor=[child, parent, ...] and flows
up, and the parent no longer re-emits a duplicate terminal output event
(full suppression, matching adk-python's _output_delegated + output_for).
Resume attributes a descendant's output to its delegating ancestors via
OutputFor. Every output event records OutputFor (own path minimum),
mirroring adk-python _enrich_event.

Built on the temp integration branch (#960 + #920 + #966); rebase onto v2
once those merge.
Base automatically changed from wolo/run_node_use_as_output to v2 June 8, 2026 10:50
…sOutput

Add NodeInfo.MessageAsOutput: when set and Event.Output is nil, readers
derive the node's output from the event's model text. The static and
dynamic schedulers both honor it (Output wins, message text is the
fallback), mirroring adk-python's _track_event_in_context. Empty text is
a valid output, matching python; AgentNode's own empty-text-skips
behavior is unchanged.

This lets a delegated child whose message IS its output (e.g. an LlmAgent
node) promote its text to the parent via WithUseAsOutput, and feeds it to
a successor on a normal handoff.
@wolo-lab wolo-lab force-pushed the wolo/message-as-output branch from 6024efc to f620edd Compare June 8, 2026 11:30
@wolo-lab wolo-lab marked this pull request as draft June 8, 2026 11:38
Complete the MessageAsOutput feature to match adk-python's single
mechanism, where a node sets Event.Output and NodeInfo.MessageAsOutput
together:

- Producer: synthesizeAgentOutput now stamps NodeInfo.MessageAsOutput
  when it derives output from model text (mirrors
  process_llm_agent_output), so the flag is present in history.
- Resume reader: collectNodeOutputs derives a node's output from the
  model message when an event is flagged MessageAsOutput and carries no
  explicit Output (mirrors _reconstruct_node_states' use_message_as_output),
  so a message-as-output node recovers its output on resume.

Previously the flag was only read (live, via childEventOutput) but never
produced and never consumed on resume.
@wolo-lab wolo-lab marked this pull request as ready for review June 8, 2026 11:54
@wolo-lab wolo-lab merged commit 92cdfe2 into v2 Jun 9, 2026
3 checks passed
@wolo-lab wolo-lab deleted the wolo/message-as-output branch June 9, 2026 09:08
wolo-lab added a commit that referenced this pull request Jun 9, 2026
Resolves conflicts from v2's #966 (MessageAsOutput) and #987
(isolation_scope) landing while this OutputFor stack was in review.

Conflict resolutions (keep this branch's OutputFor delegation model):
- session.go: keep NodeInfo.OutputFor field; drop v2's stale TODO note.
- dynamic_scheduler.go: keep full-suppression (stamp OutputFor on the
  child event) over v2's drop-and-re-emit-on-parent approach.
- persistence.go: keep OutputFor-based resume attribution to ancestors.
- persistence_test.go / run_node_test.go: keep the OutputFor tests and
  drop v2's duplicate parent-re-emit variants.
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.

2 participants