Events

The event system lets you observe graph execution without modifying your workflow logic. Events are emitted at key points — run start/end, node start/end, routing decisions — and delivered to processors you provide.

  • Event types - Immutable dataclasses for each execution milestone

  • EventProcessor - Sync base class for consuming events

  • AsyncEventProcessor - Async-aware variant for async runners

  • TypedEventProcessor - Auto-dispatches to typed handler methods

  • RichProgressProcessor - Hierarchical Rich progress bars out of the box

Overview

from hypergraph import SyncRunner, RichProgressProcessor

runner = SyncRunner()
result = runner.run(graph, inputs, event_processors=[RichProgressProcessor()])

Events flow through this pipeline:

Runner emits event → EventDispatcher → each EventProcessor.on_event()

All dispatch is best-effort: a failing processor never breaks execution.


Event Types

All events inherit from BaseEvent and are frozen dataclasses (immutable after creation).

BaseEvent

Every event carries tracing context: run_id groups events from the same execution, span_id uniquely identifies the scope, and parent_span_id links nested graphs to their parents.

RunStartEvent

Emitted when a graph run begins.

RunEndEvent

Emitted when a graph run completes (successfully or not).

NodeStartEvent

Emitted when a node begins execution.

NodeEndEvent

Emitted when a node completes successfully.

NodeErrorEvent

Emitted when a node fails with an exception.

RouteDecisionEvent

Emitted when a routing node (@route or @ifelse) makes a decision.

InterruptEvent

Emitted when execution pauses for human-in-the-loop input.

StopRequestedEvent

Emitted when a stop is requested on a workflow.

CacheHitEvent

Emitted when a node result is served from cache instead of being executed.

InnerCacheEvent

Emitted when a hypercache-decorated call happens inside a running node. This bridge activates when hypercache is installed, including via pip install 'hypergraph[cache]'. The event is emitted when the installed Hypercache version exposes its public observer API.

Event (Union Type)


Processor Interfaces

EventProcessor

Base class for synchronous event consumers.

Example — logging processor:

AsyncEventProcessor

Extends EventProcessor with async variants. The async runner prefers on_event_async and shutdown_async when available, falling back to sync methods otherwise.

TypedEventProcessor

Auto-dispatches on_event to typed handler methods. Override only the events you care about — unhandled types are silently ignored.

Example — timing processor:


RichProgressProcessor

Hierarchical Rich progress bars for graph execution. Requires the rich package.

Usage

Constructor

Args:

  • transient - If True (default), progress bars are removed after completion. Set to False to keep them visible.

  • force_mode - Controls output mode:

    • "auto" (default): detect via stdout.isatty()

    • "tty": force Rich live bars

    • "non-tty": force plain-text milestone logging (useful for CI/log pipelines)

Visual Output

Single run:

Nested graph:

Map operation:

Map with failures:

Non-TTY Milestones

In non-TTY mode, map progress is logged at fixed milestones (10%, 25%, 50%, 75%, 100%) instead of rendering live bars:

Visual Conventions

Icon
Meaning

📦

Regular node (depth 0)

🌳

Nested graph node (depth > 0)

🗺️

Map-level progress bar

Indentation reflects nesting depth. Failed nodes show [red]FAILED[/red] in the description.


EventDispatcher

Manages processor lifecycle and event delivery. You typically don't interact with this directly — runners create it internally from event_processors.


Event Sequence

A typical DAG run emits events in this order:

For cached nodes, the sequence includes a CacheHitEvent:

For map operations, each item gets its own RunStartEvent/RunEndEvent pair nested under the map's span:

For nested graphs, parent_span_id links inner events to the outer run:

Last updated