Metadata-Version: 2.4
Name: kindred-tracer
Version: 1.1.0
Summary: Kindred Tracer SDK for Python - Auto-instrumentation for AI agents
Author-email: Kindred <dev@kindred.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/aryanmundre/Kindred
Project-URL: Repository, https://github.com/aryanmundre/Kindred
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.24.0
Requires-Dist: opentelemetry-api>=1.20.0
Requires-Dist: opentelemetry-sdk>=1.20.0
Requires-Dist: opentelemetry-instrumentation-httpx>=0.41b0
Requires-Dist: opentelemetry-instrumentation-requests>=0.41b0
Provides-Extra: requests
Requires-Dist: requests>=2.25.0; extra == "requests"
Provides-Extra: otel
Requires-Dist: opentelemetry-api>=1.20.0; extra == "otel"
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == "otel"
Requires-Dist: opentelemetry-instrumentation-httpx>=0.41b0; extra == "otel"
Requires-Dist: opentelemetry-instrumentation-requests>=0.41b0; extra == "otel"
Provides-Extra: all
Requires-Dist: requests>=2.25.0; extra == "all"

# kindred-tracer

Kindred Tracer SDK for Python - Auto-instrumentation for AI agents.

This package uses **OpenTelemetry** HTTP client auto-instrumentation (`httpx`, `requests`) to capture outbound calls, categorizes them as LLM calls or tool executions, and exports logs to the Kindred log-search system (`POST /api/logs/ingest`).

## Installation

```bash
pip install kindred-tracer
```

Or with optional dependencies:

```bash
pip install kindred-tracer[all]  # Includes requests support
```

## Usage

### Basic Usage

Just call `kindred_tracer()` once at startup, and all HTTP requests will be automatically intercepted and logged:

```python
from kindred_tracer import kindred_tracer
import openai

# At startup - initialize the tracer
kindred_tracer()

# Your agent code here - no wrapping needed!
# All HTTP requests will be automatically logged
client = openai.OpenAI()
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Hello!"}]
)
```

### Async Usage

Works the same way with async code:

```python
import asyncio
from kindred_tracer import kindred_tracer
from openai import AsyncOpenAI

# Initialize once at startup
kindred_tracer()

async def main():
    # No wrapping needed - all requests are automatically logged
    client = AsyncOpenAI()
    response = await client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Hello!"}]
    )

asyncio.run(main())
```

## Configuration

Set the following environment variables:

- `KINDRED_API_KEY` (required) - Your Kindred API key for authentication
- `KINDRED_API_URL` (optional) - Base URL for Kindred API, defaults to `https://api.usekindred.dev`
- `KINDRED_SESSION_ID` (optional) - Session identifier. If not set, a UUID will be auto-generated
- `KINDRED_AGENT_ID` (optional) - Agent identifier
- `KINDRED_RUN_ID` (optional) - Run identifier

You can also pass these values directly to `kindred_tracer()`:

```python
from kindred_tracer import kindred_tracer

# Initialize with explicit values
kindred_tracer(session_id='session-123', agent_id='agent-456', run_id='run-789')
```

## How It Works

1. **Simple Initialization**: Call `kindred_tracer()` once at startup to set session context and ensure instrumentation is active.

2. **Auto-instrumentation**: OpenTelemetry instruments `httpx` and `requests` outbound calls (sync and async). This covers OpenAI SDK v1+ (uses `httpx` internally).

3. **Context**: `session_id`, `agent_id`, and `run_id` are stored in `contextvars` and attached to HTTP spans so concurrent tasks stay isolated.

4. **Request Detection**:
   - **LLM Calls**: Detected by hostname (e.g., `api.openai.com`, `api.anthropic.com`) → logged as `role: "agent"`
   - **Tool Calls**: Any other hostname → logged as `role: "tool"`

5. **Batch export**: Spans are exported via OpenTelemetry `BatchSpanProcessor` (batched, non-blocking relative to your app code).

## Log Format

Logs are automatically formatted and sent to `${KINDRED_API_URL}/api/logs/ingest` with the following structure:

```python
{
    "session_id": str,
    "timestamp": str,  # ISO 8601
    "role": "user" | "agent" | "tool" | "system",
    "content": str,
    "agent_id": str | None,
    "run_id": str | None,
    "meta": {
        "type": "llm_generation" | "tool_execution",
        "request_id": str,
        "host": str,
        "method": str,
        "path": str,
        "request_headers": dict,
        "request_body": str | None,
        "response_status": int | None,
        "response_headers": dict,
        "response_body": str | None,
        "duration_ms": float | None,
        "session_chain_id": str,  # OpenTelemetry trace id (hex)
        "log_id": str,             # OpenTelemetry span id (hex)
        "parent_id": str | None,   # Parent span id when present
        "tool_calls": list | None,  # Extracted from OpenAI JSON responses when safe
    }
}
```

## Flushing Logs

Before shutting down your application, you can flush any pending logs:

```python
from kindred_tracer import flush

# On shutdown
flush()
```

## Security

The tracer automatically sanitizes sensitive headers before logging:
- `Authorization`
- `x-api-key`
- `api-key`
- `x-auth-token`
- `cookie`

## Supported LLM Providers

The tracer automatically detects requests to:
- OpenAI (`api.openai.com`)
- Anthropic (`api.anthropic.com`)
- Google Gemini (`generativelanguage.googleapis.com`)
- Cohere (`api.cohere.com`)
- Mistral (`api.mistral.ai`)

## Example

Here's a complete example:

```python
from kindred_tracer import kindred_tracer, flush
import openai
import os

# Set your API key
os.environ['KINDRED_API_KEY'] = 'your-api-key-here'

# Initialize the tracer (reads session_id from KINDRED_SESSION_ID env var, or auto-generates)
kindred_tracer()

# Your agent code - all HTTP requests are automatically logged
client = openai.OpenAI()
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Hello!"}]
)

# Before shutdown, flush any pending logs
flush()
```

## Requirements

- Python 3.10+
- `httpx>=0.24.0` (ingest transport)
- `opentelemetry-api`, `opentelemetry-sdk`
- `opentelemetry-instrumentation-httpx`, `opentelemetry-instrumentation-requests`

## License

MIT
