Skip to main content

immersive-oa-sdk

OpenTelemetry instrumentation for AI applications, from Immersive AI Security.

immersive-oa-sdk gives you visibility into what your AI application is actually doing. One call sets up the instrumentation an AI app needs — LLM, agent and tool calls, plus the HTTP and messaging layers around them — and sends a copy of that trace data to Observe & Assess, where it is assessed for AI security risk.

If your application doesn't use OpenTelemetry yet, immersive-oa-sdk sets it up for you. If it already does, immersive-oa-sdk adds to that setup and never replaces it. Your own observability vendor keeps receiving everything it receives today.

Requirements

Python 3.11 or newer.

OpenTelemetry 1.45 or newer (contrib 0.66b0 or newer). immersive-oa-sdk relies on internals of opentelemetry.sdk, opentelemetry.attributes and several opentelemetry.instrumentation.* packages, so it is tested against every OpenTelemetry release in that range.

Install

Install immersive-oa-sdk from PyPI, with the openllmetry or openinference extra for LLM, agent and MCP spans (see LLM, agent and MCP calls). The package imports as immersive_oa_sdk.

pip install "immersive-oa-sdk[openllmetry]"
# or
uv add "immersive-oa-sdk[openllmetry]"

Quickstart

This sends a small FastAPI app's spans to Observe & Assess.

  1. In Observe & Assess, add a project on the Projects page. Copy the ingest token it shows: it's shown only once.

  2. Install immersive-oa-sdk, fastapi and uvicorn, and in main.py call immersive_oa_sdk.configure() before you create the FastAPI app:

    import fastapi
    
    import immersive_oa_sdk
    
    immersive_oa_sdk.configure()
    app = fastapi.FastAPI()
    
    
    @app.get("/hello")
    def hello() -> dict[str, str]:
        return {"hello": "world"}
    
  3. Run it with your token, your Observe & Assess address, and a name and environment for the service:

    export IMMERSIVE_API_KEY=<token>
    export IMMERSIVE_ENDPOINT=https://<your Observe & Assess address>
    export OTEL_SERVICE_NAME=hello
    export OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=dev
    uvicorn main:app --port 8000
    
  4. Call your app with curl http://localhost:8000/hello. Within a few seconds the project in Observe & Assess shows the dev environment.

Configuration

configure() reads these, and its keyword arguments of the same name win over them:

Variable Argument Default What
IMMERSIVE_API_KEY api_key none, required The project's ingest token.
IMMERSIVE_ENDPOINT endpoint none, required Base URL of your Observe & Assess instance; /v1/traces is appended.
IMMERSIVE_CA_CERT ca_cert the system trust store Path to a CA bundle for that endpoint.
IMMERSIVE_CAPTURE_CONTENT capture_content true false keeps prompt and completion text off GenAI spans.
IMMERSIVE_ENABLED true false turns the SDK off without removing the call.
service_name OTEL_SERVICE_NAME The service's name, unless the app registers its own tracer provider.

configure() never raises and never stops your app. A missing endpoint or token, or a malformed token, logs one warning and leaves export off.

It never reads OTEL_EXPORTER_*, so your own exporters keep their endpoint, headers and certificates and ours never picks them up. It does follow the standard variables that describe your app rather than an exporter:

  • OTEL_SERVICE_NAME names the service, and OTEL_RESOURCE_ATTRIBUTES sets its environment, as deployment.environment.name=<environment>. Spans with no environment are filed under default. Both apply to your own OpenTelemetry pipeline too.
  • OTEL_TRACES_SAMPLER picks the sampler when immersive-oa-sdk registers the tracer provider. Assessment requests are always sampled whatever it says.
  • OTEL_PROPAGATORS keeps your propagators; ours is added alongside. Keep baggage in it, or assessment requests are correlated only in the first service they reach.
  • OTEL_PYTHON_DISABLED_INSTRUMENTATIONS turns off any of the bundled instrumentations, by the names opentelemetry-instrument uses.
  • OTEL_SEMCONV_STABILITY_OPT_IN, if you set it, picks the HTTP attributes. Otherwise HTTP spans carry the stable ones.

What's captured

configure() turns on the instrumentation for each of these that is installed, unless you instrument it yourself:

  • Web frameworks: FastAPI, Starlette, Flask, Django and aiohttp.
  • HTTP clients: requests, httpx, urllib3 and aiohttp.
  • gRPC, client and server.
  • Messaging: Celery, Kafka (kafka-python and confluent-kafka), RabbitMQ (pika and aio-pika), and SQS through boto3 clients.
  • GenAI, with an extra: OpenAI, Anthropic, LangChain and LangGraph, and MCP, prompts and completions included unless you turn content capture off.

Every span the app creates, through these or its own tracing, is exported to Observe & Assess, and to your own exporters as well if you have them.

Call configure() early

Call configure() once, at start-up, before you create your web framework's app object, and create it through the framework's module, as below, rather than with a class you imported earlier, such as from fastapi import FastAPI. configure() turns on the HTTP instrumentation, which replaces the app class on the framework's module, so an app created from the original class isn't traced:

import fastapi

import immersive_oa_sdk

immersive_oa_sdk.configure()
app = fastapi.FastAPI()

If you instrument a web framework, HTTP client or messaging library yourself, for example with FlaskInstrumentor().instrument(), do that before configure() too, which leaves it as you set it up. Called afterwards, OpenTelemetry ignores it, along with its options.

Call configure() at start-up in the workers that consume your queues too, before they start consuming. A message published while handling an assessment request carries its request_id and sampling decision, so the worker's spans join the request's trace.

Apps that already use OpenTelemetry

If your application registers its own tracer provider, call immersive_oa_sdk.configure() after it does: immersive-oa-sdk then adds its exporter to your provider, which keeps your resource and sampler. OpenTelemetry ignores a tracer provider registered after the first, so calling configure() first would leave your own provider unused.

Wrap your sampler in immersive_oa_sdk.sampler() too, so that requests sent by an Observe & Assess assessment are always sampled. Everything else is still sampled as your own sampler decides:

import immersive_oa_sdk
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.sampling import ParentBased, TraceIdRatioBased

provider = TracerProvider(
    resource=Resource.create(),
    sampler=immersive_oa_sdk.sampler(ParentBased(TraceIdRatioBased(0.1))),
)
trace.set_tracer_provider(provider)
immersive_oa_sdk.configure()

configure() logs a warning if your provider's sampler isn't wrapped. If immersive-oa-sdk registers the provider itself, its sampler is already wrapped and follows OTEL_TRACES_SAMPLER for everything else.

If the service you assess calls other services of yours that also use immersive-oa-sdk, keep their samplers ParentBased, as in the example above. Only the service that verifies an assessment request, normally the one you assess, always samples it; the services it calls keep their spans only if their sampler follows its decision. ParentBased is the OpenTelemetry default. If you set OTEL_TRACES_SAMPLER, use one of its parentbased_* values.

LLM, agent and MCP calls

LLM, agent and MCP spans come from an extra, so you keep the GenAI instrumentation you may already run. immersive-oa-sdk[openllmetry] adds OpenLLMetry's instrumentation for OpenAI, Anthropic, LangChain and LangGraph, and MCP, and immersive-oa-sdk[openinference] adds OpenInference's for the same libraries. configure() turns each on when its library is installed. A library your app already instruments, with OpenLLMetry or OpenInference, is left as it is.

Install one extra. With both, configure() warns and turns on only one flavour, so no call is traced twice: the one your app already instruments a library with, or else OpenLLMetry.

Those spans record prompt and completion text, which Observe & Assess checks for AI security risk. To keep it out, pass capture_content=False to configure() or set IMMERSIVE_CAPTURE_CONTENT=false. That turns off OpenLLMetry's own content capture for the whole process, including any OpenLLMetry instrumentation of your own. OpenInference reads its switches when it's turned on, so OpenInference instrumentation of your own is covered only if you turn it on after configure().

Agents built by hand

An agent written straight against an LLM SDK, rather than a framework such as LangGraph, gets spans for its LLM calls but none for the agent or its tools, so it doesn't appear in Observe & Assess's agent inventory. Trace it with immersive_oa_sdk.agent() and its tools with immersive_oa_sdk.tool(), as decorators on sync or async functions, or as context managers:

import immersive_oa_sdk


@immersive_oa_sdk.tool("search")
async def search(query: str) -> str: ...


@immersive_oa_sdk.agent("planner")
async def plan(goal: str) -> str:
    return await search(goal)


with immersive_oa_sdk.agent("planner"):
    ...

The agent's name is how it appears in Observe & Assess, so keep it stable. Both are harmless without configure().

Limitations

  • Samplers downstream must be parent-based. A service the assessed one calls, with a sampler that isn't ParentBased, may drop an assessment request's spans.
  • Every hop must be instrumented. A service, or a library in one, that doesn't pass the trace context and baggage on breaks the chain: everything past it is traced without the request's request_id, so it isn't correlated with the assessment.
  • Forwarding through your own collector gives observability, not assessment correlation. Spans your collector forwards to Observe & Assess from apps without immersive-oa-sdk are stored and scanned, but only immersive-oa-sdk in the app verifies an assessment request's marker and tags its spans with the request_id.
  • With OpenInference, agents are LangChain runs. OpenInference has no agent span, so the first span of each LangChain run, a LangGraph graph's, is reported as an agent named after it. A sub-agent inside another isn't told apart from a plain graph node. An OpenAI or Anthropic call LangChain makes is traced twice, once by each library's instrumentation; the second span sits under your request rather than the graph, so it names no agent. OpenInference instruments only openai 2.8, anthropic 1.8 and mcp 1.24 or newer.
  • MCP 2 isn't instrumented with OpenLLMetry yet, and SQS through raw botocore clients, rather than boto3, is traced without carrying context.

Metadata

Release files for immersive-oa-sdk 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for immersive-oa-sdk 0.1.0
File Size Uploaded Provenance Actions
immersive_oa_sdk-0.1.0.tar.gz 39.1 kB With provenance Details for immersive_oa_sdk-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for immersive-oa-sdk 0.1.0
File Interpreter ABI Platform Actions
immersive_oa_sdk-0.1.0-py3-none-any.whl Python 3 none any Details for immersive_oa_sdk-0.1.0-py3-none-any.whl

Total release size: 85.0 kB

Release files / immersive_oa_sdk-0.1.0.tar.gz

Download URL immersive_oa_sdk-0.1.0.tar.gz
Size 39.1 kB
Tags Source
SHA-256 checksum
How to use checksums
5958bbf032b8350b65aded84a45b3cdd5c434618f9e29cf919f856635a4eaed4
BLAKE2b-256 checksum
How to use checksums
f4acd55495d3bbc7b180c07d048f80beb9c35294b89c5c5e4785d6c9552770ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Release files / immersive_oa_sdk-0.1.0-py3-none-any.whl

Download URL immersive_oa_sdk-0.1.0-py3-none-any.whl
Size 45.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fb97a83a77e6d37f877a16a428671fbe475c92bc1008c0283e9c802e40497078
BLAKE2b-256 checksum
How to use checksums
65d52b2d828be0de5fd9d027dcfd13354a52841d23647d0d19c4e55a06c110c6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Security for immersive-oa-sdk 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for immersive_oa_sdk-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page