Skip to main content
The read/query half of the monitoring contract. Implement only if the backend has a read API. A read-incapable backend still exposes a reader object, but its methods raise MonitoringReadNotSupportedError on call (never a silent no-op). OpenTelemetry has no read/query standard — each backend invents its own read surface — so this face is the abstraction’s real value.

MonitoringReader

tai42_contract.monitoring.reader.MonitoringReader
Query totals/analytics and the runtime span window.

Members

query_metrics

tai42_contract.monitoring.reader.MonitoringReader.query_metrics
Totals / analytics screen — server-side aggregation. Counts (runs, tags), total cost, total tokens, latency, grouped by the requested dimensions. Parameters

list_spans_in_window

tai42_contract.monitoring.reader.MonitoringReader.list_spans_in_window
The smallest spans that ran in the half-open window [t0, t1). CONTRACT GUARANTEE: exactly one item per tool/node execution in the window. Every reader performs this tool-granularity selection — it is not an optional filter. run scopes to a single run (one trace); None = all runs in the window. kind narrows WITHIN the tool-granularity set (never widens or overrides the guarantee). filter applies the neutral MonitoringFilter clauses (tags live here, not as a discrete param). order_by sorts the result; omitted ⇒ newest-first (start desc). An unsupported order_by.field or filter clause raises MonitoringReadNotSupportedError. Parameters

get_trace

tai42_contract.monitoring.reader.MonitoringReader.get_trace
Fetch one COMPLETE trace (top-level attrs + every observation, with full input/output) for replay / evaluation / normalization. Always returns a trace or raises — never None. An absent trace raises TraceNotFoundError; a transient/backend failure (e.g. a timeout) propagates its error so the caller sees the failure and may retry. Distinct from list_spans_in_window (trimmed dashboard units). Parameters

list_traces

tai42_contract.monitoring.reader.MonitoringReader.list_traces
List complete traces (each with its full observation set) matching the filters. An individual trace that cannot be fetched is kept in place with fetch_error set (not skipped), so one bad trace neither fails the batch nor silently vanishes. from_timestamp / to_timestamp bound the trace timestamp to the half-open window [from, to); either may be omitted for an open end. filter applies the neutral MonitoringFilter clauses (tags live here, not as a discrete param). order_by sorts the result; omitted ⇒ newest-first (timestamp desc). Sortable fields: timestamp, total_cost, name, id, latency, total_tokens — of these total_cost / latency / total_tokens rank globally (see OrderBy); the rest sort natively. An unsupported order_by.field or filter clause raises MonitoringReadNotSupportedError. Parameters

MonitoringWriter

tai42_contract.monitoring.writer.MonitoringWriter
Emit traces/spans/events, supply callbacks, and manage lifecycle. Every backend implements this face.

Members

start_span

tai42_contract.monitoring.writer.MonitoringWriter.start_span
Open a span for the duration of the block, yielding a Span handle. model / model_parameters carry GENERATION-span detail. model_parameters is open-time only (known before the call); model and usage_details can be amended later via the handle’s Span.update. A no-op under an active disable() block. Parameters

record_span

tai42_contract.monitoring.writer.MonitoringWriter.record_span
Record an already-closed span with EXPLICIT start / end times. For a span whose execution window cannot be timed live in-process — work that ran across a pause and is reported afterwards. start / end are wall-clock datetime; the backend converts as needed. trace_context.trace_id is REQUIRED — the explicit-time path has no ambient context to fall back to, so a missing trace_id RAISES (a caller bug); parent_span_id nests the span. Backend emission failures are caught + logged like the other emit methods. Parameters

create_event

tai42_contract.monitoring.writer.MonitoringWriter.create_event
Record a point-in-time event, carrying input / output. Parameters

update_current_span

tai42_contract.monitoring.writer.MonitoringWriter.update_current_span
Mutate the CURRENT (ambient) span without opening a new one. Targets the span opened by the nearest enclosing start_span block (or the callback-handler span if none). Per-generation token/cost is recorded via the held Span.update handle, not here. Parameters

trace_attributes

tai42_contract.monitoring.writer.MonitoringWriter.trace_attributes
Set trace-level name/tags/metadata on the ambient trace for the block. Parameters

current_trace_id

tai42_contract.monitoring.writer.MonitoringWriter.current_trace_id
The active ambient trace id, or None if no trace is active. Used to gate conditional emits (if writer.current_trace_id():) so none fire outside a trace.

inject_context

tai42_contract.monitoring.writer.MonitoringWriter.inject_context
Build the opaque downstream-propagation blob merged into the langgraph RunnableConfig. Carries ctx.tags + ctx.metadata. Parameters

get_monitoring_callbacks

tai42_contract.monitoring.writer.MonitoringWriter.get_monitoring_callbacks
The LangChain/LangGraph callback handlers appended to the langgraph config["callbacks"]. The caller builds ctx (keeping the auto-generated-trace-id fallback); the impl reads its fields to construct the vendor handler. Parameters

scope

tai42_contract.monitoring.writer.MonitoringWriter.scope
Bind tracing to a project (public_key) for the block. Mirrors a single-backend multi-project switch. OTel-native backends may no-op it; a real failure must raise (cross-project leak risk). Parameters

disable

tai42_contract.monitoring.writer.MonitoringWriter.disable
Suppress emission within the block. The backend’s tracing-producing methods (and the handlers from get_monitoring_callbacks) MUST honor this. A backend that never emits may no-op it; an emitting backend may not.

flush

tai42_contract.monitoring.writer.MonitoringWriter.flush
Flush any buffered telemetry.

shutdown

tai42_contract.monitoring.writer.MonitoringWriter.shutdown
Tear the client down so the next use rebuilds clean (fork-safety). Must fully evict the underlying client, not merely flush — a forked child inherits dead background threads otherwise.