Metadata-Version: 2.4
Name: kindred-tracer
Version: 1.0.0
Summary: Kindred Tracer SDK for Python - Auto-instrumentation for AI agents
Author-email: Kindred <dev@kindred.com>
License: 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: License :: OSI Approved :: MIT License
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: wrapt>=1.14.0
Requires-Dist: httpx>=0.24.0
Provides-Extra: requests
Requires-Dist: requests>=2.25.0; extra == "requests"
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 automatically intercepts HTTP requests from your AI agent, categorizes them as LLM calls or tool executions, and exports logs to the Kindred log-search system.

## 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 up global context and enable interception.

2. **Auto-instrumentation**: The tracer automatically patches `httpx.Client.request` and `httpx.AsyncClient.request` when initialized. This is **critical** because OpenAI SDK v1+ uses `httpx` internally.

3. **Global Context**: Uses a global context that applies to all HTTP requests after initialization.

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. **Non-blocking Export**: Logs are batched and exported in a background thread to avoid slowing down your agent.

## 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,
        "tool_calls": list | None,  # Extracted from OpenAI responses
    }
}
```

## 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+
- `wrapt>=1.14.0` (for safe monkey-patching)
- `httpx>=0.24.0` (for HTTP client and patching)

## License

MIT
