Skip to content

openarmature.observability

openarmature.observability — cross-backend observability surface.

Two layers:

  • Core (this module + correlation.py): always available, no extra dependencies. Exposes :func:current_correlation_id and :func:current_active_observers — the ContextVar primitives that every backend mapping consumes.
  • Backend mappings (under observability.otel and future observability.langfuse etc.): gated behind optional dependencies (pip install openarmature[otel]). Importing the subpackage without the extras installed raises an informative ImportError pointing the caller at the install command.

At v1.0 launch the backend mappings will lift into sibling packages (openarmature-otel, openarmature-langfuse) — until then they live here under per-backend subpackages so the layering is established up front.

current_active_observers

current_active_observers() -> (
    tuple[SubscribedObserver, ...]
)

Return the observer tuple in scope for the current node body (or empty tuple outside any invocation).

Capability code that needs to emit observer events from outside the engine's per-step machinery (e.g., the llm-provider span hook inside OpenAIProvider.complete) reads this to find which observers should receive the event. Combined with the engine's delivery queue, this preserves strict serial event ordering across all event sources within an invocation.

Returns an empty tuple when no invocation is active, by design — callers can iterate without a None check.

current_attempt_index

current_attempt_index() -> int

Return the attempt_index of the node currently executing, or 0 outside any node body. Retry middleware bumps this per attempt; the OTel observer uses it to disambiguate per-attempt spans when an LLM call happens inside a retried node body.

current_correlation_id

current_correlation_id() -> str | None

Return the correlation ID for the current invocation, or None if no openarmature invocation is in scope.

The correlation ID is readable from anywhere within an invocation's async call tree — node bodies, middleware, observers — without explicit threading through function arguments. This is the public reader.

Returns None outside an invocation (e.g., at module import time, inside a test that runs without going through invoke()). Callers MUST handle the None case rather than asserting a string is always present.

current_dispatch

current_dispatch() -> Callable[[NodeEvent], None] | None

Return the engine's dispatch callable for the current invocation, or None outside any invocation.

Capability code emitting observer events from inside a node body calls this to put a NodeEvent-shaped record on the engine's delivery queue. The queue's serial worker preserves per-invocation event ordering across all event sources (engine, checkpoint, LLM provider, future backends).

current_fan_out_index

current_fan_out_index() -> int | None

Return the fan_out_index of the node currently executing, or None outside any fan-out instance body (top-level nodes, subgraph dispatch, between nodes).

current_invocation_id

current_invocation_id() -> str | None

Return the engine-minted invocation ID for the current invocation, or None if no openarmature invocation is in scope.

Every invocation produces a unique UUIDv4 invocation_id, framework-generated, surfaced as the openarmature.invocation_id attribute on the invocation span + on every per-backend record. This is the public reader for backend mappings (OTel, future Langfuse) that need to populate that attribute.

current_namespace_prefix

current_namespace_prefix() -> tuple[str, ...]

Return the namespace prefix of the node currently executing, or the empty tuple outside any node body.

The empty-tuple default makes top-level (outside-invocation) and between-nodes (e.g., middleware bodies) calls fall back to invocation-level parenting cleanly.