Run Telemetry
Export metadata-only run events to logging, metrics, and tracing systems.
#Run Telemetry
maivn.telemetry publishes each customer-visible SDK run event as a stable, versioned, metadata-only object. Use it to connect mAIvn runs to an existing metrics, logging, or tracing pipeline without depending on SDK internals.
from maivn.telemetry import RunTelemetryEvent, register_listener
def observe(event: RunTelemetryEvent) -> None:
print(event.event_name, event.session_id, event.status)
with register_listener(observe):
response = agent.invoke('Inspect the fixture.')The contract requires Python 3.10 or newer.
#Public contract
The dedicated module exports:
from maivn.telemetry import (
TELEMETRY_SCHEMA_VERSION,
RunTelemetryEvent,
RunTelemetryScope,
TelemetryListener,
TelemetrySubscription,
TokenUsageTelemetry,
ToolCallTelemetry,
register_listener,
)TELEMETRY_SCHEMA_VERSION is currently "1". These names intentionally stay in maivn.telemetry rather than expanding the maivn root namespace.
RunTelemetryEvent is frozen and rejects unknown fields. Its schema contains:
- version, event name and kind, stream position, and timestamp
- event, session, thread, parent-session, root-event, and correlation IDs
- status and duration
- agent and swarm scope names
- tool call ID, name, type, namespace, and version
- input, output, cache, reasoning, and total token counts
There is no message, prompt, tool argument, tool result, final result, raw event, or payload field. Unknown future event types fail closed: they retain only the safe top-level envelope and use event_kind="unknown"; their payload is not copied.
Privacy warning A telemetry backend is persistent third-party storage. This SDK release is metadata-only and provides no content-export flag. Event arrival form is not a privacy boundary: the runtime can send customer-visible response content that is already resolved. The allowlist never reads content-bearing fields, so neither resolved values nor shielded placeholders can enter listener events or adapter spans. Content export will require a future, upstream unhydrated telemetry-form event stream and an additive schema evolution.
#Listener execution model
Listeners run synchronously inline, in registration order, on the current SDK stream thread or async task. A slow listener therefore delays the run.
- Return promptly.
- Move heavy work onto your own bounded queue or worker.
- The SDK creates no implicit worker, performs no buffering or silent dropping, and does not retry delivery.
- One listener exception is isolated; later listeners still receive the event and the run continues.
TelemetrySubscription.close()is idempotent, and subscriptions are context managers.
This explicit model preserves ordering and loss semantics. If a listener queues work, queue capacity, overflow behavior, retry, and shutdown belong to that listener.
#OpenTelemetry adapter
Install the optional API integration:
pip install "maivn[otel]"The extra adds opentelemetry-api only. The adapter does not install or configure an OpenTelemetry SDK, provider, processor, or exporter. Applications own those choices.
from maivn.telemetry import register_listener
from maivn.telemetry.opentelemetry import OpenTelemetryAdapter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
adapter = OpenTelemetryAdapter(tracer=provider.get_tracer('my.application'))
subscription = register_listener(adapter)
try:
response = agent.invoke('Inspect the fixture.')
finally:
subscription.close()
adapter.shutdown()
provider.shutdown()Install the SDK and exporter packages required by your application separately. For the example above, that includes opentelemetry-sdk and opentelemetry-exporter-otlp.
Use a batch span processor for exporter I/O. The adapter itself performs only in-memory tracer API operations on the synchronous listener path.
#Span mapping
- Each session becomes a
maivn.runinternal span. - Each tool call becomes an
execute_tool {tool_name}internal child span. - Existing active trace context parents the run span.
- Final and error events end the run and set OpenTelemetry status.
- Incomplete spans end when
OpenTelemetryAdapter.shutdown()is called. - Recent replay of terminal events is idempotent, and completed-ID retention is bounded for long-lived application processes.
The adapter uses applicable gen_ai.* attributes for operation, conversation, tool, and input/output usage metadata. Additional maivn.* attributes carry schema version, run identifiers, timing, cache/reasoning usage, and scope names. It emits no provider-cost, routing, prompt, message, argument, or result data.
#Why this is a separate surface
maivn.events.AppEvent is designed for content-rich backend/frontend event delivery, so exposing it directly to persistent telemetry listeners would put privacy behind downstream filtering. Agent-only instrumentation would miss developers who consume direct Client.stream_session() or Client.thread_events() streams. SDK-owned background dispatch would add queue, loss, and shutdown semantics that the hook contract does not hide.
The terminal reporter remains on its existing hydrated stream. Its job includes rendering customer-visible response content, so moving it to this metadata-only contract would change behavior rather than prove the telemetry schema.
#Runnable example
The demos package includes demos/features/observability/opentelemetry_export.py. With the local stack running and MAIVN_DEV_API_KEY or MAIVN_API_KEY present in the current process:
cd apps/maivn-demos
uv run python -m demos.features.observability.opentelemetry_exportIt calls one local fixture tool and prints the run trace, tool child span, and token attributes from an in-memory exporter. It does not load a dotenv file.