Metadata-Version: 2.4
Name: ttt-otel
Version: 0.1.0
Summary: OpenTelemetry SpanProcessor that seals LLM traces into the Proof-of-Time chain
License: BSL-1.1
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: opentelemetry-sdk>=1.20
Requires-Dist: blake3>=0.3
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-timeout>=2.1; extra == "dev"
Dynamic: license-file

# ttt-otel

OpenTelemetry `SpanProcessor` that seals every LLM trace span into the
**Proof-of-Time (PoT)** chain via [api.kenosian.com](https://api.kenosian.com).

Install it alongside any OTel-compatible LLM framework (Langfuse, Phoenix,
OpenLLMetry, …) to get cryptographic, tamper-evident audit trails for every
agent interaction — without modifying your existing tracing code.

---

## How it works

```
LLM agent span ends
       │
       ▼
 TTTSpanProcessor.on_end()        ← non-blocking, span is never mutated
       │
       ▼
 Canonical fields extracted
 (trace_id, span_id, name, model,
  blake3(input), blake3(output), timestamps)
       │
       ▼
 content_hash = blake3(canonical_json)
       │
       ▼
 POST /pot/generate               ← background thread, never blocks export
   body: {eventId: content_hash,
          prevEventId: <last_hash>}
       │
       ▼
 Server returns {pot_hash, signature, timestamp_ns}
 Seal stored in-memory (+ optional file persist)
```

**Privacy**: raw prompt / completion text is *never* sent to the PoT server.
Only the blake3 hash of each field travels over the wire.

---

## Quick start

```python
from opentelemetry.sdk.trace import TracerProvider
from ttt_otel import TTTSpanProcessor

provider = TracerProvider()
provider.add_span_processor(
    TTTSpanProcessor(api_key="<YOUR_TTT_API_KEY>")  # or os.environ["TTT_API_KEY"]
)
```

---

## Tamper detection

```python
from ttt_otel import verify
from ttt_otel._hash import canonical_fields_from_span

# Re-derive the hash from the original span and check it on the server
result = verify(
    canonical_fields_from_span(span),
    api_key="<YOUR_TTT_API_KEY>",
)
print(result["valid"])          # True  → seal matches
print(result["chain_intact"])   # True  → causal chain unbroken
```

If the span's output was modified after sealing, `content_hash` will differ
from the sealed `event_id` on the server, so `verify()` returns `valid=False`.

See `examples/tamper_demo.py` for a self-contained 30-second demo.

---

## Environment variables

| Variable | Default | Description |
|---|---|---|
| `TTT_API_KEY` | *(required)* | API key (`kns-…`) for api.kenosian.com |
| `TTT_SERVER_URL` | `https://api.kenosian.com` | Override for self-hosted deployments |

---

## Installation

```bash
pip install ttt-otel          # once published to PyPI
# or, from source:
pip install .
```

---

## Running tests

```bash
pytest
```

---

## Works with any OpenTelemetry backend

`TTTSpanProcessor` is a standard `SpanProcessor`.  It attaches to any
`TracerProvider` alongside an OTLP exporter — the two processors run
independently.  You only need to swap the exporter's endpoint and auth header.

| Backend | OTLP/HTTP endpoint | Auth header |
|---|---|---|
| **Langfuse** ✅ | `https://cloud.langfuse.com/api/public/otel/v1/traces` | `Authorization: Basic base64(pk:sk)` |
| **Arize Phoenix** ✅ | Local: `http://localhost:6006/v1/traces` · Cloud: `https://app.phoenix.arize.com/v1/traces` | Cloud: `Authorization: Bearer <api-key>` |
| **MLflow 3.6+** ✅ | `http://<tracking-server>/v1/traces` | `x-mlflow-experiment-id: <id>` |
| Any OTLP-compatible collector | Per-collector docs | Per-collector docs |

> **Helicone note**: Helicone is an LLM proxy/gateway, not an OTLP backend.
> It does not expose an OTLP `/v1/traces` ingest endpoint.  Use Arize Phoenix
> or MLflow if you need a direct OTLP-compatible observability backend.

---

## Examples

| File | What it shows |
|---|---|
| `examples/tamper_demo.py` | 3-span agent session, one span tampered, tamper detected |
| `examples/langfuse_otel.py` | Langfuse OTLP pipeline + TTTSpanProcessor |
| `examples/phoenix_otel.py` | Arize Phoenix OTLP pipeline + TTTSpanProcessor (local & cloud) |
| `examples/mlflow_otel.py` | MLflow 3.6+ OTLP pipeline + TTTSpanProcessor |
