OpenTelemetry interoperability
opentine v0.8 can act as both a sink and a source for OpenTelemetry GenAI provenance. Import normalizes supported OpenTelemetry content into the sameTraceEvent model as native recording. Export renders a loaded run as GenAI spans or a complete OTLP/JSON document.
Export a portable run
1import json
2from pathlib import Path
3
4from opentine import Run, to_otel_genai, to_otel_genai_document
5
6run = Run.load("run.tine")
7spans = to_otel_genai(run)
8document = to_otel_genai_document(run, service_name="research-agent")
9
10Path("run.otlp.json").write_text(json.dumps(document), encoding="utf-8")
to_otel_genai() returns a list of span dictionaries.to_otel_genai_document() returns a Python dictionary containing a complete OTLP/JSON export document. Both functions are read-only: they do not write a file, open a network connection, or transmit data to a backend.
# Write a complete OTLP/JSON document
tine export run.tine --output run.otlp.json
# Send it to a literal loopback OTLP/HTTP endpoint
tine export run.tine --endpoint http://127.0.0.1:4318tine export writes the same document to standard output or a file, or posts it to an OTLP/HTTP endpoint. Cleartext HTTP is refused unless the host is a literal loopback address or the operator passes--allow-insecure explicitly.
Export a repository run
1from opentine import Repo, to_otel_genai_document
2
3repo = Repo.open(".")
4run = repo.load_run("heads/main")
5document = to_otel_genai_document(run, service_name="agent")
The same API accepts a v2 Run, a loaded portable artifact, a v3 repository run, one TraceEvent, or an iterable of events. Pass the returned document to the exporter or transport your observability stack expects.
Import from the shell
# Complete OTLP/JSON document, priced before it is written
tine import run.otlp.json --format otel-json --price --save run.tine
# A JSON array or JSONL stream of GenAI spans
tine import spans.jsonl --format otel-spans --repo . --ref heads/importedotel-json accepts complete OTLP/JSON, a spans wrapper, or one span object. otel-spans accepts a JSON array or one span per line. See tine import for destination and overwrite rules.
Modern GenAI message content
The importer and exporter understand classic OpenTelemetry semconv 1.27gen_ai.prompt and gen_ai.completion, plus semconv 1.36 structured gen_ai.input.messages andgen_ai.output.messages, their JSON-string attribute forms, message and choice span events, and flattened OpenLLMetry and OpenInference shapes. The structured conversation remains available when a span also carries classic scalar content, and a disagreement is recorded as an import warning. The exporter emits a schema URL, complete usage dimensions, and an appropriate span kind for each event.
Provider identity and post-hoc pricing
v0.8 reads gen_ai.system or gen_ai.provider.nameinto the event's opaque provider field. Together with model and usage, that gives an imported trace enough recorded identity for post-hoc pricing. Pass --price during import to store the derived billing record before the run is first written, or runtine price later for a read-only calculation.
Round-trip boundary
Export and import preserve the GenAI fields the importer understands, including trace, span, parent identity, provider, model, content, and normalized usage. v0.10 drops source billing and keeps source cost only asopentine.source_reported_cost. Use --price for catalog-derived imported totals; an imported billing status cannot make a call free. Do not treat the operation as a byte-for-byte archive conversion: timestamps are represented through floating-point seconds and null attributes are omitted.
Exported spans can contain recorded prompts, completions, and tool content. Inspect the document before sending it outside your trust boundary. The v0.7.1 and v0.7.2 hardening fixes are shipped in the current release; see the release-status guide for that history.