Metadata-Version: 2.4
Name: ontos-observability-otel
Version: 0.1.1
Summary: One-line OpenTelemetry onboarding for the Ontos observability app: traces, cost, and the answer contract (question, answer, context, tokens).
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: opentelemetry-sdk
Requires-Dist: opentelemetry-exporter-otlp-proto-http
Provides-Extra: fastapi
Requires-Dist: opentelemetry-instrumentation-fastapi; extra == "fastapi"
Provides-Extra: flask
Requires-Dist: opentelemetry-instrumentation-flask; extra == "flask"
Provides-Extra: django
Requires-Dist: opentelemetry-instrumentation-django; extra == "django"
Provides-Extra: requests
Requires-Dist: opentelemetry-instrumentation-requests; extra == "requests"
Provides-Extra: httpx
Requires-Dist: opentelemetry-instrumentation-httpx; extra == "httpx"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"

# ontos-observability-otel

One-line OpenTelemetry onboarding for the Ontos observability app. Two calls send everything the
app needs to trace, cost, judge and compare your agent's answers: the question, the answer, the
evidence context, the token usage and the model, tagged with your customer/environment/domain.

## Install

```
pip install ontos-observability-otel
```

## Use

```python
from ontos_observability_otel import observe, record_answer

observe(customer="sigma", environment="dev", domain="my-agent",
        endpoint="https://<observability-host>:4318", token="<your ingest token>")

# after your agent answers a question:
record_answer(
    question=user_question,
    answer=agent_answer,
    context=evidence,            # what the answer was grounded on (rows, documents, SQL results)
    model="claude-haiku-4-5",
    input_tokens=usage.input_tokens,
    output_tokens=usage.output_tokens,
)
```

To also measure latency, wrap the work instead:

```python
from ontos_observability_otel import answer

with answer(user_question) as rec:
    result = my_agent.ask(user_question)
    rec.record(answer=result.text, context=result.evidence, model=result.model,
               input_tokens=result.input_tokens, output_tokens=result.output_tokens)
```

Everything can also come from the environment, so no code changes per deployment:
`ONTOS_OTLP_ENDPOINT`, `ONTOS_TOKEN`, `ONTOS_CUSTOMER`, `ONTOS_ENVIRONMENT`, `ONTOS_DOMAIN`,
`ONTOS_VARIANT` (defaults to `baseline`), `OTEL_SERVICE_NAME`.

## What each field buys you

- `question` / `answer`: the trace, the review queue, and the relevance judge.
- `context`: the groundedness judge grades the answer AGAINST this evidence; without it,
  hallucination cannot be measured.
- `model` + `input_tokens` / `output_tokens`: real cost per request and per day.
- `customer` / `environment` / `domain`: how the dashboard segments and filters everything.
  `domain` is yours to organize by (one value per app or agent works well).
- `ontos.variant` is stamped automatically (`baseline`). The value `ontos` is RESERVED for the
  Ontos runtime, so the Ontos-vs-baseline comparison is always trustworthy; the SDK refuses it.

## Already on OpenTelemetry?

You do not need this package: keep your setup and stamp the same span attributes
(`ontos.question`, `ontos.answer`, `ontos.context`, `ontos.customer`, `ontos.environment`,
`ontos.domain`, `gen_ai.request.model`, `gen_ai.usage.input_tokens`,
`gen_ai.usage.output_tokens`) on the span that carries each answer, and point your OTLP/HTTP
exporter at `<endpoint>/v1/traces` with the bearer token.

## Design

Standard OpenTelemetry, no proprietary tracer, no Ontos IP (scorers, grounding and comparison
live server-side). Best-effort by contract: no endpoint or missing dependency means a no-op; the
host application is never broken by telemetry.

Optional auto-instrumentation extras: `ontos-observability-otel[fastapi]`, `[flask]`, `[django]`,
`[requests]`, `[httpx]`.
