Metadata-Version: 2.4
Name: freesolo
Version: 0.1.0
Summary: Decorator-based LLM tracing package with OpenAI and Anthropic client instrumentation.
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: ruff>=0.11.0; extra == 'dev'
Provides-Extra: examples
Requires-Dist: anthropic>=0.40.0; extra == 'examples'
Requires-Dist: openai>=1.0.0; extra == 'examples'
Description-Content-Type: text/markdown

# freesolo

`freesolo` is a Python tracing package for the Reinforcement Labs app.

It is designed for the lowest-friction integration possible:

1. Install the package
2. Configure one endpoint + API key
3. Start a trace once
4. Add `@trace()` to your functions
5. Optionally wrap your OpenAI, Anthropic, or Google client for automatic provider spans

## Install

```bash
cd tracing
uv sync
```

To run the bundled example apps:

```bash
cd tracing
uv sync --extra examples
```

## Environment

The package reads these environment variables by default:

- `FREESOLO_BASE_URL`
- `FREESOLO_API_KEY`

The frontend app must also have:

- `FREESOLO_API_KEY`
- `SUPABASE_SECRET_KEY`

The canonical database schema lives in `frontend/supabase/migrations/`.
There is no separate tracing-side migration folder because both the ingest API
and the Supabase project are owned by the frontend app in this repo.

Runnable examples live in [`examples/`](./examples/README.md). They will
autoload env vars from `frontend/.env`, `tracing/.env`, or `tracing/examples/.env`.

## Quickstart

```python
from openai import OpenAI
from freesolo import configure, instrument_openai, start_trace, trace

configure(
    base_url="https://your-app.com",
    api_key="freesolo_api_key",
)

client = instrument_openai(OpenAI())

@trace()
def run_agent(question: str) -> str:
    result = client.chat.completions.create(
        model="gpt-4.1",
        messages=[
            {"role": "user", "content": question},
        ],
    )
    return result.choices[0].message.content or ""


with start_trace("support-agent-run"):
    print(run_agent("How do I reset my password?"))
```

## What Gets Stored

- Trace metadata if you explicitly pass it to `start_trace(..., metadata=...)`
- Spans from decorators
- OpenAI / Anthropic / Google request + response payloads
- Token usage when available
- Image inputs summarized safely instead of storing full base64 blobs

## Notes

- If you do nothing except add `@trace()`, you still get useful spans.
- Use `start_trace(trace_id=...)` when you want several decorated functions to land in one trace.
- If you also wrap the LLM client, you get dedicated provider/model spans.
- Delivery is best-effort by default. Trace ingestion failures do not break your app.
