Python reference
Generated from the glassflow-rius 0.14.0 docstrings, covering the
Python SDK’s public API surface module by module. Wording fixes happen
upstream in the SDK repository, never here.
rius.client
SDK entrypoint: configure OpenTelemetry and export GenAI traces via OTLP.
build_span_exporter
def build_span_exporter(config: GlassflowConfig) -> SpanExporterBuild the default OTLP/HTTP span exporter for a resolved config.
Arguments:
config- A resolved configuration; the exporter posts toconfig.traces_endpointwithconfig.headers.
Returns:
A ready-to-use OTLP/HTTP SpanExporter.
GlassflowClient Objects
class GlassflowClient()Handle over a configured tracer provider.
Returned by init. Exposes the lifecycle operations (flush,
shutdown) and tracer access for the pipeline it owns; the resolved
configuration is available as client.config.
register_workspace
def register_workspace(alias: str, api_key: str) -> NoneAdd (or rotate the key of) a workspace destination at runtime.
Requires routing to be enabled at init time via workspaces=
(an empty dict opts in with no static routes). Spans started inside
rius.workspace(alias) are then exported with api_key.
get_tracer
def get_tracer(name: str = TRACER_NAME) -> trace.TracerReturn a tracer bound to this client’s provider.
Arguments:
name- Instrumentation scope name; defaults to the SDK’s own.
flush
def flush(timeout_millis: int = 30_000) -> boolForce-flush pending spans and report delivery.
Returns True only when the queue drained within timeout_millis
AND the most recent export attempt succeeded. Earlier releases
reported queue drain alone, so it returned True even while every
batch was being rejected (e.g. 401 on a bad API key). A False return
therefore means either a flush timeout or that spans are currently
not being delivered; the log carries the distinction.
shutdown
def shutdown() -> NoneDrain pending spans and stop. Releases the global init() slot.
Also stops the heartbeat thread and sends its final stopped ping,
so the backend can tell a clean shutdown from a vanished agent.
init
def init(*,
endpoint: str | None = None,
api_key: str | None = None,
service_name: str | None = None,
headers: dict[str, str] | None = None,
disabled: bool | None = None,
sample_rate: float | None = None,
capture_content: bool | None = None,
mask: Callable[[Any], Any] | None = None,
instruments: Sequence[str] | None = None,
span_exporter: SpanExporter | None = None,
heartbeat: bool | None = None,
heartbeat_interval: float | None = None,
agent_name: str | None = None,
heartbeat_transport: Callable[[dict[str, Any]], None] | None = None,
connectivity_transport: ProbeTransport | None = None,
partial_spans: bool | None = None,
partial_spans_delay: float | None = None,
session_id: str | None = None,
workspaces: dict[str, str] | None = None,
workspace_exporter_factory: ExporterFactory | None = None,
set_global: bool = True) -> GlassflowClientInitialize the SDK: build a tracer provider that exports OTLP traces.
Calling init() again while a global client is active logs a warning and
returns the existing client unchanged (the OpenTelemetry global tracer
provider is write-once); call shutdown() on it first to reconfigure.
Arguments:
endpoint- Base OTLP endpoint. Traces are sent to<endpoint>/v1/traces.api_key- API key; injected as anAuthorization: Bearerheader.service_name- Value for theservice.nameresource attribute.headers- Extra headers for the OTLP exporter.disabled- If True, no exporter is attached (spans are dropped).sample_rate- Head sampling ratio 0.0-1.0 (whole-trace). Default 1.0.capture_content- If False, strip prompt/response content at export. Default True.mask- Redact content attribute values at export (applies to all spans).instruments- Auto-instrumentation selection.None(default) enables every bundled instrumentor whose package is installed; a list restricts to those names;[]disables auto-instrumentation. Instrumentors are process-global, so withset_global=Falsethey are only enabled wheninstrumentsis passed explicitly.span_exporter- Override the default OTLP exporter (useful for testing).heartbeat- Enable the agent-lifetime heartbeat thread (RIUS_HEARTBEAT; on by default, set False to opt out). Pings<endpoint>/v1/heartbeatfrom init until process exit so the platform can tell a live-but-idle agent from a vanished one. Eachinit()mints one instance id, sent both in heartbeat payloads and on every span as theservice.instance.idresource attribute, so the platform can join the two and count replicas. Fork caveat: a child forked afterinit()heartbeats under a fresh id, but its spans keep the parent’s (the OTel Resource is immutable), identifying the pre-fork process family; for exact per-worker span identity, callinit()after the fork (e.g. in gunicorn’spost_fork).heartbeat_interval- Seconds between pings (default 15, clamped to[5, 300]; the backend derives staleness from this).agent_name- Identity heartbeats group under; defaults toservice_name.heartbeat_transport- Override the heartbeat HTTP transport (useful for testing, likespan_exporter).connectivity_transport- Override the HTTP send used by the one-shot background connectivity check (useful for testing). The check POSTs an empty OTLP request at init and logs an actionable warning on 401/403, unreachable host, or other non-2xx, so a bad key or endpoint is visible immediately instead of surfacing as silently missing traces.session_id- Process-wide session id (RIUS_SESSION_ID), stamped assession.idon every span so the platform groups this process’s traces into one session. For one-run-per-process agents; a server handling many sessions scopes each one withrius.session()instead, which overrides this default.workspaces- Enable multi-workspace routing: a mapping of alias to API key. Spans started insiderius.workspace(alias)are exported with that workspace’s key; spans outside any scope use the defaultapi_key. Pass{}to opt in with no static routes and register destinations later viaregister_workspace(). One trace must stay inside one workspace; seerius.workspace.workspace_exporter_factory- Override how per-workspace exporters are built from an API key (useful for testing, likespan_exporter). Defaults to the standard OTLP exporter against the configured endpoint.set_global- Register the provider as the global OpenTelemetry provider.
get_tracer
def get_tracer(name: str = TRACER_NAME) -> trace.TracerReturn a tracer from the globally configured provider.
register_workspace
def register_workspace(alias: str, api_key: str) -> NoneAdd (or rotate the key of) a workspace destination on the global client.
The module-level twin of client.register_workspace(). Requires a
global init(workspaces=...) to have opted into routing.
rius.observe
The @observe decorator: trace the developer’s own functions.
Wraps sync, async, generator, and async-generator functions (and methods),
recording timing, inputs/outputs, and exceptions as an OpenTelemetry span.
Spans nest automatically via OTel context propagation and are exported through
whatever provider init() configured (a no-op if the SDK was never initialized).
observe
def observe(func: Callable[..., Any] | None = None,
*,
name: str | None = None,
capture_input: bool = True,
capture_output: bool = True,
kind: SpanKind = SpanKind.CHAIN) -> AnyDecorate a function so each call is traced as a span.
Usable bare (@observe) or parameterized (@observe(name=..., ...)).
Supports sync functions, async def functions, generators, and async
generators; for generators the span covers the whole iteration and the
tracing context is attached only around each step. Exceptions are
recorded with ERROR status and always re-raised.
Arguments:
func- The decorated function (filled in by bare@observeusage).name- Span name; defaults to the function’s__qualname__.capture_input- Record call arguments as JSON ininput.value.capture_output- Record the return value as JSON inoutput.value.kind- Span taxonomy (openinference.span.kind); defaultCHAIN.
Returns:
The wrapped function (or a decorator, when used parameterized).
rius.spans
Manual span API.
Two surfaces, following the OpenTelemetry / Langfuse / Laminar convention:
start_as_current_spanis the context manager: it activates the span in the OTel context (so children nest under it) and auto-ends it.start_spanis manual: it returns anObservationyou must.end(). The span is parented to the current span at creation but is NOT set as current and does NOT auto-record exceptions. For lifetimes awithblock can’t express (streaming, callbacks, passing a span across boundaries).
start_generation / start_as_current_generation are the LLM-specialized
equivalents.
Observation Objects
class Observation()Handle for annotating a span from start_span / start_as_current_span.
Wraps an OpenTelemetry span and exposes the annotation surface for generic
(non-LLM) spans: input, output, and arbitrary attributes. Inputs and
outputs are serialized to JSON (with a repr fallback) and truncated at
8192 characters.
set_input
def set_input(value: Any) -> NoneRecord the span input (the input.value attribute).
Arguments:
value- Any value; serialized to JSON with areprfallback.
set_output
def set_output(value: Any) -> NoneRecord the span output (the output.value attribute).
Arguments:
value- Any value; serialized to JSON with areprfallback.
set_attribute
def set_attribute(key: str, value: Any) -> NoneSet an arbitrary attribute on the underlying span.
Arguments:
key- Attribute name.value- An OpenTelemetry-compatible attribute value.
update
def update(*, input: Any = None, output: Any = None) -> NoneRecord input and/or output in one call.
Arguments:
input- When notNone, forwarded to :meth:set_input.output- When notNone, forwarded to :meth:set_output.
end
def end() -> NoneEnd the underlying span.
Required for spans created with start_span; spans from
start_as_current_span end automatically when the block exits.
start_span
def start_span(name: str,
*,
kind: SpanKind = SpanKind.CHAIN,
input: Any = None) -> ObservationCreate a span and return an Observation. You MUST call .end().
The span is parented to the current span at creation, but is not set as the
current span and does not auto-record exceptions. Use start_as_current_span
for block-scoped tracing.
start_as_current_span
@contextmanager
def start_as_current_span(name: str,
*,
kind: SpanKind = SpanKind.CHAIN,
input: Any = None) -> Iterator[Observation]Open a span as the current span and yield an Observation; auto-ends.
Exceptions raised in the block are recorded and set the span status to ERROR
(OpenTelemetry’s start_as_current_span default), then re-raised.
rius.generation
LLM generation capture helpers.
start_as_current_generation (context manager) and start_generation (manual,
requires .end()) open an LLM-kind span and return a Generation handle for
recording gen_ai-native attributes (messages, model, usage, finish reason). LLM
spans are therefore readable by any gen_ai-compatible consumer.
Generation Objects
class Generation()Handle for recording gen_ai attributes on an LLM span.
Returned by start_generation and start_as_current_generation.
Messages passed to :meth:set_input / :meth:set_output are normalized
to the GenAI message shape ({"role", "parts": [...]}): bare strings,
OpenAI-style dicts (including tool_calls and tool responses), and
multimodal content lists are all accepted.
set_input
def set_input(messages: Messages) -> NoneRecord the request messages (gen_ai.input.messages).
Arguments:
messages- A string or list of messages in any supported format; bare strings default to theuserrole.
set_output
def set_output(messages: Messages) -> NoneRecord the response messages (gen_ai.output.messages).
Arguments:
messages- A string or list of messages in any supported format; bare strings default to theassistantrole.
set_response_model
def set_response_model(response_model: str) -> NoneRecord the model that produced the response (gen_ai.response.model).
Arguments:
response_model- Model identifier as reported by the provider, which may differ from the requested model.
set_usage
def set_usage(*,
input_tokens: int | None = None,
output_tokens: int | None = None,
cache_read_input_tokens: int | None = None,
cache_write_input_tokens: int | None = None,
reasoning_output_tokens: int | None = None) -> NoneRecord token usage (gen_ai.usage.* attributes).
Send token counts, never cost: cost is computed server-side from model pricing.
Pass provider-reported values as-is; never pre-add anything. Per the
GenAI conventions, gen_ai.usage.input_tokens is the total
including cached tokens (the cache counts are subsets of it).
Anthropic’s API reports input_tokens excluding the cache counts,
and the conventions require the instrumentation to do the summing,
so when the generation’s provider is "anthropic" the emitted
total is input_tokens plus both cache counts. For every other
provider the values are recorded verbatim.
Arguments:
input_tokens- Prompt tokens consumed, when known.output_tokens- Completion tokens produced, when known.cache_read_input_tokens- Input tokens served from a provider-managed prompt cache (gen_ai.usage.cache_read.input_tokens).cache_write_input_tokens- Input tokens written to a provider-managed prompt cache (gen_ai.usage.cache_write.input_tokens, called “cache creation” by Anthropic).reasoning_output_tokens- Output tokens spent on reasoning / extended thinking (gen_ai.usage.reasoning.output_tokens). A subset ofoutput_tokens, never in addition to it: providers already include reasoning tokens in the output total, so pass both as reported and do no arithmetic.
record_first_token
def record_first_token() -> NoneMark the arrival of the first streamed token (gen_ai.first_token event).
Call from a streaming loop when the first content chunk arrives; the
backend derives time-to-first-token as the event time minus the span
start. Idempotent: only the first call records; safe to call
unconditionally per chunk. A no-op after end().
set_finish_reasons
def set_finish_reasons(reasons: str | list[str]) -> NoneRecord why generation stopped (gen_ai.response.finish_reasons).
Arguments:
reasons- A single reason (wrapped into a list) or a list of reasons, e.g."stop","length","tool_calls".
update
def update(*,
input: Messages | None = None,
output: Messages | None = None) -> NoneRecord input and/or output messages in one call.
Arguments:
input- When notNone, forwarded to :meth:set_input.output- When notNone, forwarded to :meth:set_output.
end
def end() -> NoneEnd the underlying span.
Required for generations created with start_generation; spans from
start_as_current_generation end automatically when the block exits.
start_generation
def start_generation(name: str,
*,
model: str | None = None,
provider: str | None = None,
input: Messages | None = None,
model_parameters: dict[str, Any] | None = None,
operation: str = "chat",
reasoning_level: str | None = None) -> GenerationCreate an LLM-kind span and return a Generation. You MUST call .end().
Manual counterpart to start_as_current_generation: not set as current, no
auto-recording of exceptions.
Arguments:
name- Span name.model- Requested model (gen_ai.request.model).provider- Provider name (gen_ai.provider.name), e.g."openai".input- Request messages, recorded immediately viaset_input.model_parameters- Request parameters, each recorded asgen_ai.request.<key>.operation- Operation name (gen_ai.operation.name); default"chat".reasoning_level- Requested reasoning/thinking effort level (gen_ai.request.reasoning.level), e.g. OpenAI’sreasoning.effortvalues. Provider-defined string, recorded verbatim.
Returns:
A Generation handle; call .end() when the call completes.
start_as_current_generation
@contextmanager
def start_as_current_generation(
name: str,
*,
model: str | None = None,
provider: str | None = None,
input: Messages | None = None,
model_parameters: dict[str, Any] | None = None,
operation: str = "chat",
reasoning_level: str | None = None) -> Iterator[Generation]Open an LLM-kind span as the current span and yield a Generation; auto-ends.
Children created inside the block nest under this span, and exceptions
raised in the block are recorded with ERROR status, then re-raised.
Accepts the same arguments as start_generation.
Yields:
A Generation handle for recording messages, usage, and response
metadata; the span ends when the block exits.
rius.config
Configuration resolution for the GlassFlow SDK.
Values are resolved with the precedence: explicit arguments > environment variables > built-in defaults.
GlassflowConfig Objects
@dataclass(frozen=True)
class GlassflowConfig()Resolved, immutable SDK configuration.
Produced by resolve_config (arguments over environment over
defaults); consumed by init and build_span_exporter.
traces_endpoint
@property
def traces_endpoint() -> strFull OTLP/HTTP traces URL (<endpoint>/v1/traces).
heartbeat_endpoint
@property
def heartbeat_endpoint() -> strHeartbeat URL (<endpoint>/v1/heartbeat), same host as traces.
resolve_config
def resolve_config(*,
endpoint: str | None = None,
api_key: str | None = None,
service_name: str | None = None,
headers: dict[str, str] | None = None,
disabled: bool | None = None,
sample_rate: float | None = None,
capture_content: bool | None = None,
heartbeat: bool | None = None,
heartbeat_interval: float | None = None,
agent_name: str | None = None,
partial_spans: bool | None = None,
partial_spans_delay: float | None = None,
session_id: str | None = None) -> GlassflowConfigResolve SDK configuration from arguments, environment, then defaults.
Explicit arguments win over RIUS_* environment variables, which win
over built-in defaults. sample_rate is clamped to [0.0, 1.0] with
a warning; boolean environment variables accept 1/true/yes/
on (case-insensitive).
Arguments:
endpoint- Base OTLP endpoint (RIUS_ENDPOINT).api_key- Bearer token for the managed platform (RIUS_API_KEY);Nonesends no Authorization header.service_name-service.nameresource attribute (RIUS_SERVICE_NAME).headers- Extra exporter headers; an explicitAuthorizationentry wins overapi_key.disabled- Kill switch (RIUS_DISABLED); spans are dropped in-process.sample_rate- Head-sampling ratio for root traces (RIUS_SAMPLE_RATE).capture_content- WhenFalse, content attributes are stripped at export (RIUS_CAPTURE_CONTENT).heartbeat- Enable the agent-lifetime heartbeat thread (RIUS_HEARTBEAT). On by default; setFalseorRIUS_HEARTBEAT=falseto opt out.heartbeat_interval- Seconds between pings (RIUS_HEARTBEAT_INTERVAL), clamped to[5, 300]; the backend derives staleness from this, so the bounds are part of the wire contract.agent_name- Identity heartbeats group under (RIUS_AGENT_NAME); defaults toservice_nameso the agents view and the traces view agree on what an “agent” is.partial_spans- Export a content-free pending snapshot of every sampled span at span START (RIUS_PARTIAL_SPANS), so in-flight work is visible and crashes leave a record. Off by default until the backend’s unfinished-spans storage ships.partial_spans_delay- Debounce for pending snapshots (RIUS_PARTIAL_SPANS_DELAY), clamped to[0, 60]seconds.0(default) emits at span start;Nemits only if the span is still open after N seconds; spans that finish sooner cost no network at all.session_id- Process-wide session id (RIUS_SESSION_ID), stamped assession.idon every span. For one-run-per-process agents; a server handling many sessions uses therius.session()scope instead, which overrides this default. Unset means spans outside a scope carry no session id and are grouped per trace.
Returns:
The resolved, immutable GlassflowConfig.
rius.semconv
Semantic conventions for the GlassFlow SDK.
Centralizes the OpenTelemetry instrumentation-scope name, the span-kind taxonomy,
and span attribute keys. Span kinds use the OpenInference openinference.span.kind
values (understood across the ecosystem); LLM specifics use OTel GenAI gen_ai.*.
SpanKind Objects
class SpanKind(str, Enum)Observation kind. Values are OpenInference openinference.span.kind values.
AGENT: an agent invocation or runLLM: a model call (generations use this)TOOL: a tool executionRETRIEVER: a retrieval / search stepEMBEDDING: an embedding computationCHAIN: a generic processing step (the default)
kind_attributes
def kind_attributes(kind: SpanKind) -> dict[str, str]Identity attributes for a span of kind, for setting at CREATION.
Pending snapshots (pending.py) are built at on_start, so taxonomy set
via set_attribute afterwards is invisible to them; passing these at
span creation is what makes a pending span classifiable.
set_span_kind
def set_span_kind(span: Span, kind: SpanKind) -> NoneStamp a span with its OpenInference kind and (if applicable) gen_ai operation.