/docs/sdks/python
Python SDK
Python SDK for tracing AI agents, model calls, tool calls, metadata, media, metrics, and trace reads.
Installation
pip install theta-obsrvConfiguration
API keys are project-scoped on the server. THETA_PROJECTis optional and only needed when you want explicit project filtering.
export THETA_API_KEY="tk_live_…"
export THETA_BASE_URL="https://api.obsrv.tech" # optional
export THETA_PROJECT="proj_…" # optionalTracing
with client.trace(name="checkout", run_type="prod") as t:
t.set_metadata(user_id="u_a72c", release="v3.2.1")
with t.step(name="plan", type="llm", model="claude-sonnet-4-6") as s:
s.log_message(role="user", text="Buy milk")
s.log_message(role="assistant", text="On it.")
s.set_token_usage(input=900, output=120)
s.set_metadata(provider_cost_usd=0.014)
with t.step(name="inventory.lookup", type="tool") as s:
s.log_tool_call(
name="inventory.lookup",
arguments={"sku": "milk"},
result={"in_stock": True},
latency_ms=83,
)
t.attach_image("screenshot.png")
client.flush()Agent wrapping
@client.wrap_agent("support-agent")
def agent(ctx, query):
result = call_llm(query)
ctx.on_complete(result)
return result
result, run_id = agent("Help me cancel my order")
client.record_metric("task_adherence", run_id, passed=True)Multimodal attachments
t.attach_image("./screenshot.png")
t.attach_audio(audio_bytes, mime="audio/wav")
t.attach_video("./recording.mp4")
t.attach_file("./report.pdf")
t.attach_sensor(depth_frame_bytes, modality="depth-camera")Provider integrations
from openai import OpenAI
from theta_observability.integrations import wrap_openai
oai = wrap_openai(OpenAI(), client)
oai.chat.completions.create(model="gpt-4o-mini", messages=[...])Batching and shutdown
The SDK queues traces and flushes either when the batch fills or after the configured flush interval. Short-lived scripts should flush before exit; long-lived workers can call close() during shutdown.
client.flush()
client.close()Reading data back
result = client.list_traces(
status=["error"],
metadata_filters=[{"key": "release", "value": "v3.2.1"}],
limit=50,
)
for trace in result.data:
print(trace.trace_id, trace.status, trace.latency_ms)
detail = client.get_trace("tr_…")
print(detail.name, len(detail.steps))Reference
TraceClient(api_key?, project?, base_url?, flush_interval?, max_batch?)client.trace(name, run_type=..., user_id=..., metadata=...)client.wrap_agent(name)t.step(name, type=..., model=..., metadata=...)s.log_message(role=..., text=..., images=..., attachments=...)s.log_tool_call(name, arguments, result=..., error=..., latency_ms=...)s.set_token_usage(input, output, total=None)t.set_metadata(**kwargs)andt.set_metadata_path(dot_path, value)client.record_metric(name, trace_id, passed=... | score=... | label=...)client.list_traces(...)andclient.get_trace(trace_id)client.flush()andclient.close()