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
Members
query_metrics
tai42_contract.monitoring.reader.MonitoringReader.query_metrics
list_spans_in_window
tai42_contract.monitoring.reader.MonitoringReader.list_spans_in_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
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
get_trace is the only body door. A malformed backend row fails the page loudly (never kept
as a partial row nor silently skipped).
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
RUN_ATTRIBUTION_TRACE_NAME
tai42_contract.monitoring.writer.RUN_ATTRIBUTION_TRACE_NAME
RUN_VERSION_METADATA_KEY
tai42_contract.monitoring.writer.RUN_VERSION_METADATA_KEY
MonitoringWriter
tai42_contract.monitoring.writer.MonitoringWriter
Members
start_span
tai42_contract.monitoring.writer.MonitoringWriter.start_span
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
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
input / output.
Parameters
update_current_span
tai42_contract.monitoring.writer.MonitoringWriter.update_current_span
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
user_id / session_id set the backend’s native identity dimensions
when supplied; None leaves each unset. They are optional and
keyword-only, so an existing caller that sets only name/tags/metadata is
unaffected. A ROOT version is carried inside metadata under
RUN_VERSION_METADATA_KEY (not a discrete parameter) so a backend
without a native version dimension keeps it as ordinary metadata.
Parameters
current_trace_id
tai42_contract.monitoring.writer.MonitoringWriter.current_trace_id
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
RunnableConfig.
Carries ctx.tags + ctx.metadata.
Parameters
get_monitoring_callbacks
tai42_contract.monitoring.writer.MonitoringWriter.get_monitoring_callbacks
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
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
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
shutdown
tai42_contract.monitoring.writer.MonitoringWriter.shutdown
attribute_run
tai42_contract.monitoring.writer.attribute_run
attribution on the ambient trace for the WRAPPED block.
A free function composing writer over MonitoringWriter.trace_attributes,
kept off the Protocol so structural writers conform without inheriting it. The
caller ENTERS the returned manager AROUND the whole run so the run’s spans are
created INSIDE the attribution scope. It RETURNS the manager rather than
entering it — a one-shot enter/exit here would tear the scope down before any
span exists and silently no-op the stamp.
It does NOT gate on MonitoringWriter.current_trace_id. A stamp deposited
BEFORE any trace is open is NOT lost: trace_attributes is context-scoped
(langfuse’s propagate_attributes writes the attributes into the ambient OTel
context — see propagation.py’s _set_propagated_attribute — and the span
processor lifts them onto the trace ROOT when a span is subsequently opened
inside the scope, span_processor.py). Short-circuiting to a nullcontext
when current_trace_id() is None therefore DROPPED the attribution on the
common case — a door that deposits then opens the run’s first span — so the guard
is removed. This helper is NOT itself fail-safe against a non-conforming writer: it
CALLS trace_attributes here, so a writer whose signature omits these keywords
raises a TypeError at THIS call — before any enter/exit guard inside the writer
could run — and a writer that raises on enter/exit surfaces likewise. A caller that
must not be broken by a monitoring-writer fault guards entering the returned manager
(the skeleton run seams do, logging the fault and continuing the run unattributed).
Parameters

