Skip to main content

Hue Python SDK

For frozen datasets, local experiments, custom scorers, durable retries and historical rescoring, see Local evaluations.

Python helpers around official OpenTelemetry 1.44.0 trace and log SDKs and OTLP HTTP/protobuf exporters. Provider requests run in your application. This package does not proxy model calls or configure global OTel providers.

The distribution is named hue-run (import hue_sdk). Python 3.10+ is supported by the package contract; recorded validation below identifies the tested runtime.

Install

pip install hue-run
# Or, in a uv project:
uv add hue-run

Send a trace

In the consuming application, use only public imports:

import os
from hue_sdk import Hue

with Hue(
    api_key=os.environ["HUE_API_KEY"],
    capture_content=False,  # Required: choose explicitly.
) as hue:
    project = hue.validate_project()
    with hue.context(session_id="conversation-42", user_id="observed-user-7"):
        with hue.span("agent.run") as run:
            run.set_input({"question": "What is 2 + 2?"})
            with hue.tool("add") as tool:
                tool.set_input({"a": 2, "b": 2})
                tool.set_output(4)
            run.set_output({"answer": 4})
    if not hue.force_flush():
        raise RuntimeError("Telemetry export failed; inspect Hue export_status.")

The SDK uses https://app.hue.run by default. Set base_url only for a different Hue deployment or a local receiver, using an origin without an API suffix. Existing Hue(base_url, api_key, ...) calls remain supported. The project service key determines the project. The SDK validates the project at GET /api/v1/projects/current when explicitly requested; construction itself does not perform a request. HTTP is permitted only for localhost and loopback IPs. Userinfo, query strings, fragments, paths and redirects are rejected. The key is sent only as Authorization: Bearer …; repr(hue), SDK errors and status counters omit it.

Content and semantic fields

capture_content has no default. False makes set_input, set_output and inference-log bodies omit content before it reaches an OTel queue. Explicit JSON null, empty strings and absent content stay distinct when capture is enabled. Exception recording includes the exception type and ERROR status; exception messages and stacks are always excluded by these helpers.

This setting is not a blanket PII filter. Custom attributes, span names, session/user identifiers, resource attributes, third-party instrumentors and other exporters remain under your control. The server stores received content; there is no automatic telemetry expiry. Delete scoped data explicitly when required by your retention policy.

Use redactor=lambda field, value: ... to transform content in supported helpers. It runs synchronously before serialization and export. Return a redacted JSON value; failures omit the field and increment export_status.instrumentation_failures without changing application behavior. It does not inspect arbitrary OTel attributes or logs:

def redact(field, value):
    if isinstance(value, dict):
        return {key: "[redacted]" if key == "email" else item for key, item in value.items()}
    return value

The callback should cover your actual nested input format; this small example is only a top-level dictionary transformation.

Before redaction, helpers copy supported content into detached built-in containers; in-place changes by a redactor cannot change application inputs or results. The input and the redactor's returned value each have a 1 MiB conservative value budget, 64 maximum nesting depth and 65,536 visited values/keys. Integers and integer keys are limited to 14,000 bits before decimal conversion. Final serialized content still has the 256 KiB UTF-8 JSON limit. Cyclic, nonfinite, unsupported or over-budget content is omitted and counted as an instrumentation failure. See the Python safety boundary for supported types and callback limits.

Helper Attributes / behavior
span(name) Generic input.value / output.value, optional OTel attributes and kind
model(model, provider=...) gen_ai.operation.name, gen_ai.request.model, gen_ai.provider.name; message content in gen_ai.input.messages / gen_ai.output.messages
tool(name, call_id=...) gen_ai.operation.name=execute_tool, gen_ai.tool.name, call ID, arguments and result
context(session_id=..., user_id=...) Task-local gen_ai.conversation.id / user.id on nested Hue helpers; observed users are not Hue account identities
span.set_usage(...) Nonnegative reported gen_ai.usage.input_tokens / output_tokens; None leaves a field absent
span.log_inference(input=..., output=...) Correlated gen_ai.client.inference.operation.details log, explicitly linked to that span
span.record_error(error) Exception type event and ERROR status; context managers also record escaping errors/cancellation
Hue.inject(headers) / Hue.extract(headers) W3C trace context propagation; pass extracted context to span(parent_context=...)

Tool/model metadata accepts plain strings; invalid values use stable fallback labels and increment instrumentation failures without invoking custom conversion hooks. Disabled tracing skips metadata validation.

For model helpers, pass the message representation produced by your integration. Prefer current GenAI message conventions when authoring your own messages. Use either span content or correlated logs for a given input/output, avoiding duplicate copies. Structured log fields contain JSON strings so null remains distinguishable from protobuf's absent value.

Existing instrumentation

Pass an existing opentelemetry.sdk.trace.TracerProvider through tracer_provider=provider to add Hue's exporter. Hue does not call set_tracer_provider. It exposes hue.tracer_provider, hue.tracer and hue.logger_provider for explicit integration. shutdown() closes Hue's processors; a borrowed tracer provider and its other processors stay usable. Finish traced work before shutting Hue down: spans ending or external records emitted afterward increment Hue's dropped-record counters, including emissions through a borrowed provider. New Hue helpers after shutdown are no-ops. Do not repeatedly attach Hue clients to one long-lived provider: OTel has no public processor-removal API. Create one client per provider lifecycle.

An instrumentor that accepts tracer_provider can receive hue.tracer_provider; follow that instrumentor's own capture/redaction configuration. OpenInference and other OTel instrumentors are optional dependencies, not implicitly enabled. They can emit content even when Hue helper capture is disabled. The optional compatibility group pins OpenAI 3.14.0, OpenInference OpenAI 0.1.60 and its resolved OpenInference instrumentation 0.1.63. A synthetic HTTP streaming response verifies parentage, canonical model/usage attributes and enabled/disabled message capture with TraceConfig(enable_genai_semconv=True, hide_inputs=..., hide_outputs=..., hide_input_messages=..., hide_output_messages=...). This is a tested adapter combination, not a claim about all OpenAI APIs or live-provider compatibility. See the instrumentor's official source. See the Python integration guide for application setup.

Export behavior and limits

  • Traces go to /api/v1/otlp/v1/traces; correlated logs go to /api/v1/otlp/v1/logs. Both use the official OTLP HTTP/protobuf exporter, uncompressed. The official exporter handles retryable network/service failures; Hue additionally honors 429 and Retry-After within its transport budget. There is no proprietary provider transport.
  • Exporter work and its HTTP worker run with OpenTelemetry instrumentation suppressed. Hue ignores records emitted within that suppressed scope, preventing HTTP instrumentation and exporter diagnostics from feeding back into its own queues. Application instrumentation resumes outside that scope.
  • Batches initially contain at most 64 records and are split by encoded protobuf size to fit 1 MiB, both on wire and after decoding. A single oversized record fails visibly through export status. Helper content exceeding 256 KiB UTF-8 JSON is omitted before enqueue and increments instrumentation failures; it is never silently truncated by Hue. Third-party record validation remains the receiver's responsibility. OTel's own attribute/count/environment limits can still affect externally configured providers.
  • Hue accepts at most 2,000 distinct spans per trace. This is enforced by the receiver across distributed producers; the client cannot guarantee a global count.
  • HTTP errors, malformed/non-200 success responses and OTLP partial_success rejected counts cause a failed export status. Partial rejection is not retried wholesale. Receiver error text is not echoed. A warning-only partial-success response with zero rejected records remains successful.
  • force_flush(timeout_millis=30000) drains both processors and returns False for a timeout, failed export, dropped record or instrumentation omission since this client was created. Hue's processors honor the shared deadline and serialize drains in a bounded background worker. Pending exports continue after timeout. export_status exposes cumulative failure counters. shutdown() stops new helpers, drains and closes owned exporters within the caller's wait budget; repeated calls wait for the same shutdown. After a timeout, keep the process alive and call shutdown again to confirm completion. Context-manager exit calls shutdown_safe(timeout_millis=1000); check flush explicitly when an exit code must reflect delivery failure.
  • Hue processors use the public OTel interfaces and bound each signal to 2,048 records and 8 MiB of encoded telemetry by default, including in-flight records (max_queue_size, max_queue_bytes). Dropped records and instrumentation omissions make cumulative export_status.ok false. Queue overflow, process termination and sampling can lose telemetry. Flush success reports observed exporter outcomes, not durable local delivery or proof that every application operation was instrumented. The exporter timeout controls individual export/retry operations. A caller timeout does not cancel an HTTP request already in flight; background workers continue until the operation completes.
  • A timed-out HTTP worker can retain one encoded request of up to 1 MiB per signal outside the queue counters. Later records remain queued within the configured limits until that worker finishes; shutdown counts any queued records it must discard. Queue bytes are not total process memory.
  • A flush timeout releases drain coordination so later flushes can make progress. Both signals share the caller's remaining wait budget, including time spent waiting for another flush. Shutdown's exporter cleanup can continue after the caller returns without holding that coordination lock. Repeated shutdown calls report current failures and drops as well as cleanup completion.

Confirm a trace reached Hue

Hue.verify_trace() checks a server receipt for a known trace from a real application request. It does not send a synthetic trace, invoke a model, or flush an exporter. Finish the request, then flush the provider that produced it. If you borrow a provider, call its force_flush() first, then check Hue's force_flush() result before verifying:

# Retain these IDs while your application's instrumented request runs.
# After the request finishes and the relevant providers have flushed:
confirmation = hue.verify_trace(
    request_trace_id,
    expected_span_ids=[request_span_id, model_span_id],
    required_fields=["input", "output", "model", "usage", "session"],
    timeout_millis=10_000,
)
if confirmation.verified:
    print(confirmation.receipt.trace_url)
else:
    # The latest partial receipt, or None if this trace has not appeared yet.
    print(confirmation.receipt)

Only require fields your instrumentation emits and your capture policy permits. For metadata-only capture, omit input and output. The receipt contains presence booleans and counts, not captured content. verified=True confirms the requested trace, every supplied expected span, and every required field; it does not prove that unlisted application operations were instrumented. Missing spans or fields continue polling until the deadline, then return verified=False with the latest receipt. Trace IDs must be nonzero and contain 32 lowercase hexadecimal characters; expected span IDs must be nonzero, contain 16, be unique, and number at most 100. The timeout must be positive and at most 60,000 ms.

Only trace-not-found responses, HTTP 429 and HTTP 503 are retried. Authentication, unsupported receipt endpoints, malformed responses and connection failures raise TraceVerificationError with a safe code and optional status_code; response bodies and keys are omitted. Redirects are rejected. The deadline covers connection, polling and response-body reads. An in-flight network read may finish in the background after the caller times out. This helper requires a Hue deployment that implements /api/v1/traces/{traceId}/receipt.

Supported runtimes and verification

Python 3.10+ is supported. CI tests Python 3.10 and 3.14, source imports and an independently installed wheel. Tests use synthetic loopback HTTP receivers and decode official OTLP protobuf messages to verify trace/log correlation, metadata-only capture, redaction, propagation, existing-provider ownership, authentication failures, redirects, partial rejection, retries and encoded request limits. Compatibility tests also exercise local evaluations and the optional OpenInference adapter. No live model provider is required for these checks.

See the documentation for integration guidance and troubleshooting for export failures.

Managed targets

Start a frozen dataset run in Hue while your existing agent stays in your application:

import os
from hue_sdk.managed import ManagedTargetHandler, ManagedTargetResult

def target(invocation):
    # Your function consumes unchanged inputs and verified attachment bytes.
    result = run_agent_for_evaluation(invocation)
    return ManagedTargetResult(output=result)

handler = ManagedTargetHandler(
    machine_credential=os.environ["HUE_MANAGED_TARGET_SECRET"],
    target=target,
    flush_telemetry=hue.force_flush,  # Existing client; False keeps telemetry pending.
)

Your POST route calls handler.handle(raw_body_bytes, request_headers) and returns its JSON body, status code and headers. Limit request bodies to 1 MiB; use asyncio.to_thread from an async route. The target must honor cancelled and deadline_monotonic. Use a 120-second host limit for the default 90-second callback and 30-second finalization budget.

For generated files, return ManagedOutputFile entries containing actual bytes, filename, content type and an optional primary flag. The helper claims the invocation, verifies files and saves the outcome without automatically rerunning the agent. See the managed-run guide and full adapter contract for registration, existing-provider flush callbacks and recovery. Local/CI runners remain available.

Serving safely

Use create_hue_safe for best-effort startup and enabled=False for a local kill switch. The safe constructor returns a disabled client and records an instrumentation failure if initialization fails. Disabled helpers execute application work without exporting. Initialize after fork, once per serving process. force_flush_safe(timeout_millis=1000) and shutdown_safe(timeout_millis=1000) return booleans without raising; monitor those results and export_status. Keep strict project validation and receipt/delivery checks out of customer request paths. Never rerun application work to recover telemetry.

Queue bytes bound retained telemetry rather than total RSS. Network waits have a wall-clock caller bound and at most one retained HTTP worker per signal; a stuck OS call can outlive that wait. Arbitrary user hooks and third-party instrumentation retain their own behavior. See production safety for lifecycle examples, failure tests and limitations.

Release files for hue-run 0.1.3

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

Source distribution (sdist)

Source distribution for hue-run 0.1.3
File Size Uploaded
hue_run-0.1.3.tar.gz 167.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hue-run 0.1.3
File Interpreter ABI Platform
hue_run-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 218.8 kB

Release files / hue_run-0.1.3.tar.gz

Download URL hue_run-0.1.3.tar.gz
Size 167.3 kB
Tags Source
SHA-256 checksum
How to use checksums
2c014032b8a7768da639ec726336a4ed3d867585314ca85d55ad92e8d80cb3c8
BLAKE2b-256 checksum
How to use checksums
63cac447b701d9192e7613fbb45850fc0a4facaad48cd45a0653a6fec918df86
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 17, 2026.

Transparency log

Release files / hue_run-0.1.3-py3-none-any.whl

Download URL hue_run-0.1.3-py3-none-any.whl
Size 51.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a0408f83ffafac25320f32cb18410863f049c52e8ae95e4bbd29ae64710c1693
BLAKE2b-256 checksum
How to use checksums
e4e7e74b3544c7587a7d7f9a818c2b462193997428a2c178c78c7e181915c599
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 17, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release 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