Metadata-Version: 2.4
Name: torina
Version: 0.1.2
Summary: Trace ingestion client for Torina — captures LLM agent traces and forwards them over HTTP.
Author: noahwg
Author-email: noahwg <nwg7199@gmail.com>
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Monitoring
Requires-Dist: wrapt>=1.14
Requires-Python: >=3.8
Project-URL: Homepage, https://github.com/Tribemails/torina-python-lib
Project-URL: Issues, https://github.com/Tribemails/torina-python-lib/issues
Description-Content-Type: text/markdown

# torina

Captures LLM agent traces and forwards them to Torina. **LangChain is the
only supported integration for now** — more are planned.

## Quickstart

### 1. Create an API key

Create one at [app.torina.io/profile?section=api-keys](https://app.torina.io/profile?section=api-keys).

### 2. Install

```bash
uv add torina
# or
pip install torina
```

### 3. Add instrumentation

```python
import os
import torina

torina.auto_instrument()
torina.init_logger(
    api_key=os.environ["TORINA_API_KEY"],
    project="My Project (Python)",
)
```

`auto_instrument()` patches LangChain automatically if it's installed, so
every `agent.invoke()`/`.stream()` call anywhere in your app gets captured
with no per-call-site changes.

Traces go to `https://app.torina.io/api/traces` by default. Pass `endpoint=`
or set `TORINA_ENDPOINT` to point at a self-hosted or dev instance instead.

## Capturing conversations, agent names, and metadata

These all come from LangChain's own `config`/`create_agent(name=...)`, no
Torina-specific code needed:

```python
agent = create_agent(..., name="weather-agent")  # -> payload["agent_name"]

agent.invoke(
    {"messages": [...]},
    config={
        "configurable": {"thread_id": thread_id},  # -> payload["conversation_id"]
        "metadata": {"user_id": "u_123", "plan": "enterprise"},  # -> payload["metadata"]
    },
)
```

## Manual instrumentation

For control over a specific call site instead of the global patch,
`TorinaCallbackHandler` is available directly (requires `langchain-core`):

```python
from torina.langchain import TorinaCallbackHandler

agent.invoke({"messages": [...]}, config={"callbacks": [TorinaCallbackHandler()]})
```

## dry_run

```python
torina.init_logger(dry_run=True)  # no api_key or endpoint needed
```

Traces are logged instead of sent — useful for local testing before you have
a real endpoint. Same code path either way; `dry_run` only swaps the network
call for a log line.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for local development, the release
process, and notes on how traces are structured internally.
