Skip to Content
RiusSDKInstallation and configuration

Installation and configuration

The Rius SDK for Python is published as glassflow-rius and imported as rius; it requires Python 3.10 or newer. The TypeScript SDK is published as @glassflow-ai/rius and requires Node 18 or newer. Both SDKs are open source under the MIT license, on GitHub: Python  and TypeScript .

pip install glassflow-rius

To auto-instrument the LLM libraries you use, install their extras (see Integrations):

pip install "glassflow-rius[openai]" # one library pip install "glassflow-rius[instruments]" # everything

An extra installs the instrumentation for a library, never the library itself: glassflow-rius[anthropic] brings in the Anthropic instrumentation and expects anthropic to already be in your environment, which it is in any project that calls Anthropic. Rius deliberately does not depend on provider SDKs, so it never pins or upgrades the versions your code runs against. If an extra is installed without its library, init() logs a DependencyConflict from OpenTelemetry and that integration stays off; see Troubleshooting. MCP needs no extra: Rius instruments it directly rather than through a separate package, so that integration turns itself on whenever mcp is importable.

Initializing

Call init() once, as early as possible in your process:

import rius client = rius.init( api_key="ri_...", service_name="my-agent", )

Every argument is optional and can also come from an environment variable. Explicit arguments win over environment variables, which win over defaults.

Naming your agent

Set service_name (RIUS_SERVICE_NAME) explicitly. It is the service.name resource attribute stamped on every span and how you find your agent in trace filters, analytics, and cost breakdowns. It defaults to unknown_service.

Optionally set agent_name (RIUS_AGENT_NAME) to control how instances group in the Agents view. It defaults to service_name; set it separately only when several services form one logical agent.

Keep the name constant across replicas and deploys. Each process start is a fresh instance under the same name, so three replicas show as three instances of one agent. Keep version numbers out of the name and put them where they belong instead:

  • service_version (RIUS_SERVICE_VERSION) is the build or release this process runs, stamped as service.version. Unset, it falls back to a service.version in OTEL_RESOURCE_ATTRIBUTES, and otherwise the attribute is left off rather than filled with a placeholder.
  • main_agent_version (RIUS_MAIN_AGENT_VERSION) is the version of the agent definition, meaning its prompt, tools, and policy, stamped as rius.main_agent.version. It moves independently of the build, so the SDK never derives one from the other.

Two more optional identity settings describe the agent itself: main_agent_id (RIUS_MAIN_AGENT_ID) is a stable identifier such as a registry id, and main_agent_description (RIUS_MAIN_AGENT_DESCRIPTION) says what the agent does. Use an id that survives restarts and deploys: an id minted at process start would turn every restart into a new agent, and service.instance.id already identifies the process.

The SDK stamps the agent’s identity under the OpenTelemetry GenAI conventions’ gen_ai.main_agent.* keys, next to the older rius.main_agent.* ones. gen_ai.main_agent.id is main_agent_id when you set it (the argument, then RIUS_MAIN_AGENT_ID), then a gen_ai.main_agent.id you already put in OTEL_RESOURCE_ATTRIBUTES, and otherwise the agent name. So without an id, renaming the agent also changes gen_ai.main_agent.id. Set main_agent_id if you want an identity that survives a rename. When the id falls back to the name, the SDK logs a one-time hint at debug level: on the rius.client logger in Python, and on the OpenTelemetry diag logger in TypeScript, which is silent unless you install one with diag.setLogger(..., DiagLogLevel.DEBUG).

Renaming does not re-key history: stored spans keep the old service.name and stay filterable under it, while the new name starts empty. In the Agents view the old name’s instances report gone and linger until their heartbeat records are garbage-collected. Treat the name as an identifier, not a label.

Configuration reference

ArgumentEnvironment variableDefaultWhat it does
endpointRIUS_ENDPOINThttps://ingest.eu.console.rius-glassflow.comBase OTLP endpoint. Traces post to {endpoint}/v1/traces.
api_keyRIUS_API_KEYNoneSent as Authorization: Bearer <key>. If you pass your own Authorization header via headers, it wins. None is valid for OTLP backends that need no auth.
service_nameRIUS_SERVICE_NAMEunknown_serviceThe service.name resource attribute on every span. Set it; it is how you find your agent later. See Naming your agent.
service_versionRIUS_SERVICE_VERSIONNoneThe service.version resource attribute, for example your release or image tag. Unset, a service.version in OTEL_RESOURCE_ATTRIBUTES applies; otherwise the attribute is omitted.
headersnone{}Extra headers for the exporter.
disabledRIUS_DISABLEDFalseKill switch. When true, no exporter is attached and spans are dropped in-process.
sample_rateRIUS_SAMPLE_RATE1.0Head sampling rate for root traces. See Sampling.
capture_contentRIUS_CAPTURE_CONTENTTrueWhen false, prompt and response content is stripped at export; metadata still flows. See Privacy controls.
masknoneNoneRedaction callable applied to content attributes at export. See Privacy controls.
instrumentsnoneNoneWhich integrations to enable: None enables all installed, [] disables, ["openai"] restricts. See Integrations.
span_exporternoneNoneOverride the OTLP exporter (mostly for tests).
heartbeatRIUS_HEARTBEATTrueThe agent-lifetime heartbeat thread: pings {endpoint}/v1/heartbeat from init() until process exit, powering the Agents view. Since 1.5.1 it needs credentials: without api_key or an Authorization entry in headers (or a custom heartbeat_transport), no heartbeat is sent. On by default since 0.10.0; set False (or RIUS_HEARTBEAT=false) to opt out. Delivery semantics in Reliability.
heartbeat_intervalRIUS_HEARTBEAT_INTERVAL15Seconds between pings, clamped to 5-300. Keep it at 15 or below: the platform marks an instance stale after 30 seconds and gone after 60 seconds without a ping, whatever the interval, so a longer interval makes a live instance flap to stale.
agent_nameRIUS_AGENT_NAMEservice_nameThe identity heartbeat instances and spans group under in the Agents view, stamped on the resource as gen_ai.main_agent.name, gen_ai.agent.name, and the deprecated rius.main_agent.name. Set it when several services are one logical agent. See Naming your agent.
main_agent_idRIUS_MAIN_AGENT_IDNoneA stable identifier for the agent this process runs, stamped as gen_ai.main_agent.id and the deprecated rius.main_agent.id. Unset, gen_ai.main_agent.id is a gen_ai.main_agent.id in OTEL_RESOURCE_ATTRIBUTES, else the agent name, so renaming the agent changes it; rius.main_agent.id is then left off. Never a per-process id.
main_agent_descriptionRIUS_MAIN_AGENT_DESCRIPTIONNoneWhat the agent does, stamped as gen_ai.main_agent.description and the deprecated rius.main_agent.description.
main_agent_versionRIUS_MAIN_AGENT_VERSIONNoneThe version of the agent definition (prompt, tools, policy), stamped as rius.main_agent.version. Independent of service_version.
heartbeat_transportnoneNoneOverride the heartbeat HTTP transport (mostly for tests, like span_exporter).
partial_spansRIUS_PARTIAL_SPANSFalseExport a content-free snapshot of every span at start, so in-flight and crashed work is visible. See Partial spans.
partial_spans_delayRIUS_PARTIAL_SPANS_DELAY0.0Seconds to hold a snapshot before sending it, clamped to 0-60. A span that finishes within the delay sends no snapshot at all.
session_idRIUS_SESSION_IDNoneProcess-wide session.id for every span, for an agent that handles one session per process. A session scope overrides it; do not set it in a server handling many users.
bridge_foreign_providerRIUS_BRIDGE_FOREIGN_PROVIDERFalseWhen another OpenTelemetry SDK (Langfuse, Traceloop, Logfire, MLflow, OpenLIT, Laminar) already owns the global tracer provider, also send that provider’s spans to Rius, so your LLM calls keep their parents. Spans whose parent Rius never received are flagged rius.parent.foreign either way.
workspacesnoneNoneMulti-workspace routing: a mapping of alias to API key. Spans inside rius.workspace(alias) export with that workspace’s key; {} opts in with routes added later via register_workspace(). See routing traces to the right workspace.
workspace_exporter_factorynoneNoneOverride how per-workspace exporters are built from an API key (mostly for tests, like span_exporter).
set_globalnoneTrueRegister the provider as the global OpenTelemetry provider.

Boolean environment variables accept 1, true, yes, or on, and 0, false, no, or off, in any case. Since 1.5.1, an unrecognized value (including an empty one) logs a warning and falls back to the default rather than being read as false. Out-of-range sample_rate values are clamped to [0.0, 1.0] with a warning.

Only the RIUS_* names are read. Releases before 1.0.0 also accepted the older GLASSFLOW_* spellings with a deprecation warning; from 1.0.0 those are ignored, so rename any that remain in your environment.

Calling init() twice

The OpenTelemetry global provider is write-once, so a second global init() while a client is active logs a warning and returns the existing client unchanged. To reconfigure, call client.shutdown() first, which drains pending spans and releases the slot. With heartbeats enabled, shutdown() also sends the final stopped ping, which is how the platform tells a clean exit from a crash (see status semantics).

If your process needs an isolated pipeline next to an existing one, use a scoped client instead:

client = rius.init(set_global=False, service_name="side-pipeline") tracer = client.get_tracer()

A scoped client does not claim the global slot, and it does not enable auto-instrumentation unless you pass instruments=[...] explicitly, because instrumentors patch libraries process-wide.

What every span carries

The SDK stamps these resource attributes on all spans it exports:

  • service.name, from your configuration, and service.version when you set one
  • service.instance.id, minted once per init(), which is the id the heartbeat reports too, so a trace can be joined to the process that ran it
  • gen_ai.agent.name, the resolved agent name
  • gen_ai.main_agent.id, gen_ai.main_agent.name, and gen_ai.main_agent.description, the OpenTelemetry GenAI conventions’ main agent. The id is the configured main agent id, otherwise the agent name (see Naming your agent). The name and description are only sent alongside the id, and the description only when set. With no id and no usable name (empty, or the unknown_service placeholder), the SDK sends none of these keys from its own settings. Any gen_ai.main_agent.* value you set yourself in OTEL_RESOURCE_ATTRIBUTES is kept, not overwritten.
  • rius.main_agent.name, rius.main_agent.id, and rius.main_agent.description, deprecated in favor of the gen_ai.main_agent.* keys and still sent through the deprecation window. rius.main_agent.name is left off when no service or agent name was configured, rather than claiming unknown_service as an identity, and rius.main_agent.id carries only an id you configured, never the name.
  • rius.main_agent.version, when set. It has no upstream equivalent and is not deprecated.
  • telemetry.distro.name: glassflow-rius and telemetry.distro.version
  • OpenTelemetry’s own telemetry.sdk.name, telemetry.sdk.language, and telemetry.sdk.version (in TypeScript since 1.2.0)

Spans created by the SDK itself use the tracer scope name rius (glassflow in releases before 1.0.0 of both SDKs).

Span attribute limit

OpenTelemetry keeps at most 128 attributes per span by default and silently drops the rest. That is too few for an auto-instrumented agent: the OpenInference instrumentors write one attribute per message field and per tool field, so a tool-calling loop with around ten tools passes 128 after roughly six to nine turns. The spans that matter most then lose data without any error. In Python the oldest keys go first, which are the model, the request parameters, the tool definitions, and the system prompt; in TypeScript the span stops accepting new keys, which are the usage, the output messages, and the finish reason.

init() therefore raises the per-span attribute count limit to 4096. If you set OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT or OTEL_ATTRIBUTE_COUNT_LIMIT to a value OpenTelemetry can use, your value wins and OpenTelemetry applies its usual precedence between the two. A blank or unusable value (not a number, or in Python not a non-negative integer) is not treated as a choice: the SDK applies 4096 instead, and the Python SDK logs a warning saying so. One exception in Python: a non-integer OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT makes OpenTelemetry itself raise when its tracing module is imported. The attribute value length is not limited; the SDK caps its own JSON attributes at 32 KB.

If you run OpenInference instrumentors without the SDK, nothing raises the limit for you; see OpenInference.

Next steps

Last updated on