.agents/skills/adk-architecture/references/architecture/node-runner.md
NodeRunner is the per-node executor. It drives BaseNode.run(),
creates the child Context, enriches events, and writes results
to ctx.
The runtime has two distinct channels for data flow:
A node writes to ctx to communicate with its parent. A node yields Events to persist data and stream messages to the user.
Orchestrator
│
├─ NodeRunner(node=child, parent_ctx=ctx)
│ │
│ ├─ _create_child_context() → child Context
│ ├─ _execute_node() → iterate node.run()
│ │ ├─ _track_event_in_context() → write to ctx
│ │ └─ _enqueue_event() → enrich + persist
│ ├─ _flush_output_and_deltas() → emit deferred output
│ └─ return child ctx
│
└─ reads ctx.output, ctx.route, ctx.interrupt_ids
Create child Context — inherits _invocation_context (shared
singleton), builds node_path from parent, assigns run_id.
Iterate node.run() — for each yielded Event:
Track in context — _track_event_in_context writes output,
route, and interrupt_ids from the event to ctx (source of truth).
Enrich — _enrich_event stamps metadata before persistence:
event.author — node name (or event_author override)event.invocation_id — from InvocationContextevent.node_info.path — full path (e.g., wf/child_a)event.node_info.run_id — unique per executionevent.node_info.output_for — ancestor paths when
use_as_output=TrueFlush deltas — for non-partial events, _flush_deltas moves
pending state/artifact deltas from ctx.actions onto the event
before enqueueing.
Enqueue — ic.enqueue_event puts the event on the shared
process queue for session persistence.
Flush deferred output — if ctx.output was set directly
(not via yield), _flush_output_and_deltas emits the output
Event after _run_impl returns. Bundles any remaining
state/artifact deltas onto the same Event.
Return child ctx — the orchestrator reads ctx.output,
ctx.route, and ctx.interrupt_ids.
use_as_output)When a child is scheduled with use_as_output=True, its output
Event also counts as the parent's output. NodeRunner:
ctx._output_delegated = True on the parentevent.node_info.output_for with ancestor paths