Commit 835b8e1
committed
Add fan-out / subgraph / detached parenting to Langfuse observer
Extends LangfuseObserver with synthetic dispatch observations
matching the OTel observer's structure. Spec §8.3 mandates Span
observations for subgraph wrappers, fan-out nodes, and per-instance
fan-out spans; §8.5 covers detached-trace mode where a configured
subgraph or fan-out gets its own Langfuse Trace and the parent's
dispatch observation surfaces metadata.detached_child_trace_ids.
_InvState gains six new fields:
- subgraph_observations: synthetic dispatch Span observations keyed
by namespace prefix (lives in main Trace for non-detached, or in
the detached Trace for detached subgraphs)
- fan_out_instance_observations: per-instance dispatch Span
observations keyed by prefix + (str(fan_out_index),)
- detached_traces: prefix -> detached trace_id mapping that switches
descendant observations onto the detached Trace
- fan_out_instance_root_prefixes: tracks detached fan-out instance
prefixes for the close path
- fan_out_parent_node_name: cache populated from fan_out_config on
the fan-out node's started event, bridging the lookup for the
per-instance attribution metadata
- detached_child_trace_ids: side-cache accumulator for the link-ids
array on dispatch observations spawning detached children
(the Protocol doesn't expose a metadata read accessor)
LangfuseObserver gains two constructor kwargs (detached_subgraphs,
detached_fan_outs) mirroring the OTel observer's surface.
_resolve_parent_observation_id rewritten with full precedence:
per-instance fan-out dispatch > subgraph dispatch (walked longest-
first) > leaf-node ancestor walk > Trace root. Same precedence
applied to _resolve_llm_parent_observation_id so an LLM call from
inside a subgraph/fan-out parents correctly.
_trace_id_for picks the right Trace (main or detached) for an
observation by walking ancestor prefixes longest-first against the
detached_traces map. Per-instance detached fan-out Traces are
keyed by prefix + (str(fan_out_index),) and checked first.
_sync_subgraph_observations is the synthesis driver: opens any
ancestor dispatch observation the leaf event needs, closes any
whose subtree we've left. Called before opening the leaf so the
parent resolver sees them. Detached fan-out instance roots are
exempted from cursor-move close — they close with the fan-out
node's own completed event.
Asymmetry documented in the helper docstrings: detached subgraphs
synthesize a second "link" observation in the main Trace (subgraphs
have no per-subgraph node event of their own, so there's no
pre-existing observation to attach the link metadata to). Detached
fan-out instances accumulate the link metadata on the fan-out
node's pre-existing leaf observation instead.
Four new unit tests cover the synthesis paths (no Langfuse spec
fixtures exist for these in v0.23.0; spec considering a follow-on
proposal to add them before v0.10.0 release):
- subgraph dispatch parents inner-node observations
- non-detached fan-out per-instance dispatches parent worker nodes
- detached subgraph splits into two Traces with the metadata link
- detached fan-out per-instance Traces with accumulating
detached_child_trace_ids array on the fan-out node
All 3 existing conformance fixtures (022-024) still pass; no
regression on linear/LLM/prompt cases.1 parent 885fee5 commit 835b8e1
2 files changed
Lines changed: 676 additions & 24 deletions
0 commit comments