v0.4.0
Spec v0.3.1 / proposal 0003: node-boundary observer hooks.
External code can now observe execution as it happens — the control-side equivalent of the data-side trace field pattern.
New public API
NodeEvent(frozen dataclass):node_name,namespacetuple,step,pre_state/post_state,error,parent_states. Exactly one ofpost_stateorerroris populated per event.ObserverProtocol: async callable receiving aNodeEvent. The parameter is positional-only so conformance isn't tied to a parameter name.CompiledGraph.attach_observer(fn) -> RemoveHandlefor graph-attached observers;invoke(state, observers=...)for invocation-scoped.CompiledGraph.drain()— awaits delivery of every event dispatched by prior invocations of this graph. Required for short-lived processes (CLIs, scripts, serverless).
Delivery semantics
- Strictly serial within an invocation: no two observers process the same event concurrently; no observer sees event N+1 until everyone has finished N.
- Order: graph-attached (outermost → innermost), then invocation-scoped — both in registration order.
- Async-from-graph:
invoke()returns when the graph reaches END regardless of queue state. - Observer exceptions are caught and reported via
warnings.warn— they don't break siblings, subsequent events, or the graph run. - Subgraph-internal events bubble up: the subgraph wrapper itself stays observer-transparent. Step counter spans the subgraph boundary;
namespaceandparent_statesextend.
Other changes
- CI workflow added at
.github/workflows/ci.yml(ruff + ruff-format + pyright + pytest). - Spec submodule pinned at v0.3.1 (corrigendum to fixture 013's YAML syntax).
See the proposal for design rationale.