Skip to main content

virgo-observe

Four Python operations for Virgo: register a client, trace an operation, attach feedback, and publish an individual product metric. Traces use OpenTelemetry; feedback and metrics use separately authorized, unsampled HTTP channels.

This checkout contains the 0.3.0 release candidate, not proof of a PyPI publication. Python 3.10+ is supported. Build/install the local artifact:

uv build packages/virgo-observe-python
pip install dist/virgo_observe-0.3.0-py3-none-any.whl

Four operations

Provision each channel's source-scoped credentials in Virgo. Never reuse the trace key as a feedback or outcome token. Configure them outside application code:

export VIRGO_API_KEY='<trace-source-key>'
export VIRGO_FEEDBACK_API_URL='https://your-api/v1/feedback-ingest/v1/events'
export VIRGO_FEEDBACK_API_TOKEN='<feedback-source-token>'
export VIRGO_OUTCOME_API_URL='https://your-api/v1/labs/<workspace-id>/outcomes:publish'
export VIRGO_OUTCOME_API_TOKEN='<outcome-publisher-token>'
from decimal import Decimal
from virgo_observe import MetricSubject, VirgoSubject, VirgoVersions, register

virgo = register(project_name="support-agent", release="release-7")

with virgo.agent_run(
    "support.resolve_ticket",
    run_ref="run-opaque-123",
    subject=VirgoSubject(account_ref="account-opaque-123"),
    versions=VirgoVersions(agent="agent-v4", prompt="prompt-v7"),
):
    # Run your agent here. Selected supported integrations emit child spans.
    with virgo.span("retrieval.context_pack", kind="RETRIEVER"):
        pass

    saved_execution = virgo.current_trace_ref()
    completed = virgo.metric(
        "resolved_ticket_value",
        observation_id="ticket-123-value",
        value=Decimal("12.34"),
        unit="USD",
        definition_version="resolved-ticket-v1",
        subject=MetricSubject("account", "account-opaque-123"),
        lineage={"producer": "ticket-service"},
    )

# Feedback may arrive later. Persist saved_execution with your own run record
# when the response/callback crosses a process boundary.
feedback = virgo.feedback(
    feedback_id="ticket-123-rating",
    trace=saved_execution,
    rating="down",
    kind="correction",
    correction="The answer should use the selected workspace.",
)

report = virgo.flush_report(timeout_seconds=5)
# Inspect report.feedback, report.metrics, and each receipt.status.
virgo.shutdown(timeout_seconds=5)

A saved TraceRef contains an external nonzero 32-character lowercase W3C trace ID and/or your opaque run reference, never a Virgo-internal ptr_… ID. An explicit reference wins over the active execution. Feedback requires one; metrics may remain deliberately unlinked. Subject references are opaque application IDs, not pre-hashed Virgo pseudonyms.

span() returns a native OpenTelemetry Span. kind is an optional AI role such as AGENT, LLM, or TOOL; otel_kind=SpanKind.CLIENT independently preserves native transport semantics. Generic spans are not inferred to be tools from parentage. agent_run(), get_tracer(), flush(), and instrumented_frameworks remain supported. Typed identity, run, release, and version arguments own their reserved attribute keys.

Point observations and real outcome windows

A metric without window is one observed event: it requires a non-null boolean/numeric value, revision 1, and no supersession. Its occurrence is captured once when called, or set explicitly with an aware occurred_at. It does not fabricate a time window or interpret False as a mature failure. Use an event KPI definition to aggregate these observations; precomputed custom KPI definitions consume windowed measurements only.

For a completed or censored outcome window, supply MetricWindow(start, end, mature_at) using timezone-aware datetimes. The order is start < end <= mature_at. An observed window must already be mature; occurred_at, if supplied, must equal its end. Supported statuses are observed, immature, proxy, right_censored, not_achieved, and reversed. Immature/right-censored values are null.

value accepts bool, int, finite float, finite bounded Decimal, or None where the status permits it. Decimal is serialized as exact decimal text, not a float. Arbitrary categorical strings are rejected. Subjects have exactly one grain: account, user, journey, conversation, session, or aggregate (without a ref). Approved lineage keys are source, source_version, definition_hash, export_id, and producer.

Corrections retain the logical observation_id, increment revision, and set supersedes_observation_id. Every revision gets a distinct stable HTTP idempotency key. Retrying an unchanged revision is a duplicate; changing its semantic value, timestamp, lineage, subject, release, versions, or execution claim is a conflict. New revisions never edit the previous record.

Privacy and integration ownership

Metadata-only is the default. capture_content=True explicitly enables content. When the argument is omitted, VIRGO_CAPTURE_CONTENT=true|false can carry an explicitly selected runtime policy. Explicit arguments win. The server's trace-source policy remains authoritative.

The Virgo exporter filters its own export representation: unapproved attributes, events (including exception content), status descriptions, link attributes, and resource/scope attributes are removed. It does not mutate spans delivered to another exporter. Operational names and approved opaque IDs remain; do not put prompts, personal data, secrets, or arbitrary content in those fields. This trace setting does not erase explicitly submitted feedback text, which follows the separately configured feedback source's policy.

Register before constructing instrumented clients. The initial tested set is native Pydantic AI, plus the OpenInference OpenAI, Anthropic, and LangChain adapters. Installing an arbitrary entry point is not a support guarantee. Use instrumentors=["openai"] (or another subset) to select an instrumentation layer, or auto_instrument=False for manual tracing.

Automatic selection gives active native Pydantic AI/LangChain instrumentation precedence over provider wrappers, preventing duplicate model spans. Overlapping provider adapters are reported as unsupported with overlapping_model_instrumentation; direct provider calls outside the selected higher-level framework then need a provider-only selection or manual spans. Existing external instrumentation is never reconfigured and is reported already_active_unverified, not healthy by inference.

Inspect virgo.registration_report for each integration's distribution version, status, ownership, and safe reason code. Discovery/activation is not proof of server delivery. Native automatic metadata-only instrumentation requires patched Pydantic AI 2.27.1+; earlier versions are skipped because retry content can leak through their native instrumentation.

The reproducible integration matrix uses real SDKs and local fake responses, including model streaming and native tool/validator retries:

Layer Tested minimum Tested selected current
OpenTelemetry SDK/exporter 1.43.0 1.44.0
Pydantic AI slim 2.27.1 2.37.0
OpenAI SDK (OI adapter 0.1.57) 1.69.0 3.7.0
Anthropic SDK (OI adapter 2.1.1) 1.0.0 1.3.0
LangChain Core (OI adapter 0.1.73) 0.3.50 1.6.1
LangChain OpenAI 0.3.12 1.6.0

Other versions are not individually certified. Install optional integrations alongside the application's existing dependencies; do not upgrade an application merely to silence an unsupported registration report.

Providers, configuration, and lifetime

register() uses an explicitly supplied SDK provider, then an existing global SDK provider, or otherwise a private provider. It never replaces the global provider. Compatible registrations share one export stream and sender with reference-counted lifetime; conflicting registrations on that provider fail. Closing one handle does not shut down another handle or the customer's provider. Final shutdown releases Virgo-owned framework wrappers only while their ownership still matches; externally installed or replaced wrappers are left untouched.

In pre-fork servers, create the provider and call register() inside each worker after it starts. Do not share a live Virgo handle or delivery receipt across a fork. Inherited handles reject operations instead of using stale threads/locks. Use explicit shutdown for short-lived jobs; process exit is not a delivery receipt.

trace_export="existing" requires an existing SDK provider, needs no Virgo trace key, and attaches no Virgo exporter. The application's exporter and privacy policy own that path; Virgo's export-local content filter does not apply to it. The independent feedback/metric channels still work.

Explicit arguments take precedence over the channel environment variables. Trace compatibility also accepts OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_HEADERS/OTEL_EXPORTER_OTLP_HEADERS, and OTEL_SERVICE_NAME. VIRGO_ENDPOINT, VIRGO_ENVIRONMENT, and VIRGO_RELEASE override hosted defaults. The project display name is never used to guess a workspace publication URL. Missing channels are permitted at registration, but publishing to one raises a configuration error.

Each record channel has its own finite in-memory queue and worker (default 512 pending events each). Payloads, occurrence times, IDs, and operational W3C headers are captured before enqueueing. Network calls suppress recursive HTTP instrumentation. At most three attempts retry transport errors, 408, 429, and 5xx responses with bounded jitter/backoff and Retry-After. Other HTTP failures are terminal; redirects never forward credentials.

Receipts expose queued, accepted, rejected, conflict, failed, or dropped states. Queue overflow is visible as dropped, not silently successful. A 202 means accepted at ingress, not normalized, linked, or successfully analyzed. flush_report() reports cumulative failures and pending records; flush() is its boolean compatibility view. Trace force-flush completion is not proof of remote ingestion.

Flush and shutdown share a total caller deadline across channels. An exporter or in-flight HTTP call can finish after the caller's deadline; Python cannot safely cancel arbitrary third-party I/O. Shutdown marks undelivered receipts failed and closes owned resources. This queue is not crash-durable: persist important application events in your own outbox and reuse their IDs when retrying after a process restart. Call shutdown during orderly teardown.

Server contract and verification

Point metrics, explicit observation/release/version fields, and durable privacy-aware correlations require the accompanying Platform server changes and forward migration 0197. Upgrade via platform-migrate; never use an SDK client-side fallback against an older window-only endpoint.

Exact links require the same tenant, workspace, environment, and permitted pseudonym scope. Multiple candidates and contradictory references abstain. Late links live in a separate projection, not edits to immutable outcome rows. Pending claims receive bounded retries and a final expiry check; missing or sampled-out traces do not prevent observation acceptance.

From the Platform repository root:

uv run ruff format packages/virgo-observe-python
uv run ruff check packages/virgo-observe-python
uv run mypy packages/virgo-observe-python/src
uv run pytest packages/virgo-observe-python/tests
uv run python packages/virgo-observe-python/scripts/check_framework_matrix.py
uv build packages/virgo-observe-python
uv run python scripts/verify_virgo_observe_distribution.py

See docs/virgo/instrumentation/python.md, docs/observability.md, and docs/virgo/instrumentation/python-release.md for server inspection and the separately authorized publication procedure.

License

The virgo-observe Python SDK is licensed under the Apache License, Version 2.0. The full license is included in this package's LICENSE file and its wheel and source distributions.

This license applies only to packages/virgo-observe-python within the Platform repository. It does not license the rest of the Platform repository or Virgo's hosted services. Third-party dependencies retain their own licenses.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

virgo_observe-0.3.0.tar.gz (45.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

virgo_observe-0.3.0-py3-none-any.whl (34.1 kB view details)

Uploaded Python 3

File details

Details for the file virgo_observe-0.3.0.tar.gz.

File metadata

  • Download URL: virgo_observe-0.3.0.tar.gz
  • Upload date:
  • Size: 45.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for virgo_observe-0.3.0.tar.gz
Algorithm Hash digest
SHA256 64c4f13dfe836a2546151879dff1a291faa0367ced61f42c5034257e9d94d388
MD5 94560910d105c816b624d0518a3fb92b
BLAKE2b-256 d5b3daba8884736cb69f2d968e678d5947b61df2f2f3f0502097201ba5e2fa1d

See more details on using hashes here.

File details

Details for the file virgo_observe-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: virgo_observe-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 34.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for virgo_observe-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 453d544d49f1bfb5c4eafc5a488d0a597a136df98d23586b0d7bdd6d45b93c08
MD5 1bc144ac3293c154076bd7623371449a
BLAKE2b-256 88bb784f40930a2c259a110f70d75bfdbb9f627199c43f56e24cb1a12c00b416

See more details on using hashes here.

Release history Release notifications | RSS feed

0.7.0

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.5

2 files

0.5.4

2 files

0.5.3

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

This release

0.3.0 This release

2 files

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