# Tracing SDK (potato_trace)

Source: https://www.potatoannotator.com/docs/agent-evaluation/tracing-sdk

**`potato_trace` is a lightweight SDK that captures your agent's runs and sends them to Potato for evaluation** — so Potato sits in the runtime path and you evaluate real runs as they happen, instead of only importing offline dumps. It is dependency-light (standard library plus `requests` at send time) and a top-level package, so importing it never pulls in a web framework.

## Quick start

```python
import potato_trace

potato_trace.configure(
    potato_url="http://localhost:8000",   # or env POTATO_TRACE_URL
    api_key="",                            # or env POTATO_TRACE_API_KEY
    project_name="my-agent",
)

@potato_trace.traceable(run_type="tool")
def search(query):
    return run_search(query)

@potato_trace.traceable(run_type="llm")
def summarize(text):
    potato_trace.add_metadata(prompt_tokens=120, completion_tokens=40)
    return call_llm(text)

@potato_trace.traceable            # the outermost call is the trace root
def agent(task):
    return summarize(search(task))

agent("weather in NYC")
potato_trace.flush()               # ensure sends finish before a short script exits
```

Nested `@traceable` calls form a **run tree**; when the root returns, the whole tree is POSTed to `/api/traces/webhook` in a background thread (tracing never blocks or crashes your agent). If no `potato_url` is configured, tracing is a safe no-op.

## API

| Symbol | Purpose |
|--------|---------|
| `configure(potato_url=, api_key=, project_name=)` | Set the global client |
| `@traceable` / `@traceable(run_type=, name=, tags=)` | Trace a function (sync or async); `run_type`: `chain` (default), `llm`, `tool`, `retriever` |
| `trace(name, run_type=...)` | Context-manager form: `with trace("step"): ...` |
| `set_outputs({...})` / `add_metadata(**kw)` | Attach outputs / token usage to the current run |
| `flush(timeout=30)` | Wait for pending background sends |

## OpenTelemetry interop (optional)

If your stack emits OpenTelemetry spans (GenAI semantic conventions), export them to Potato directly. `opentelemetry-sdk` is an optional extra:

```python
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from potato_trace.otel_exporter import build_exporter

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(build_exporter(project_name="my-agent")))
```

## Receiving the traces

On the Potato side, enable trace ingestion so the webhook accepts the runs:

```yaml
trace_ingestion:
  enabled: true
  api_key: ""    # set a key in production; the SDK sends it as a Bearer token
```

Captured traces become items you can evaluate, route with [automation rules](/docs/agent-evaluation/automation-rules), or curate into [datasets](/docs/agent-evaluation/datasets-and-experiments).

## Related

- [Full reference on Read the Docs](https://potatoannotator.readthedocs.io/en/latest/integrations/tracing_sdk/) — full SDK + OpenTelemetry API, version-matched
- [Agentic Annotation](/docs/features/agentic-annotation) — annotate the captured traces
- [Automation Rules](/docs/agent-evaluation/automation-rules) — route incoming traces automatically
