Metadata-Version: 2.4
Name: raindrop-pydantic-ai
Version: 0.0.3
Summary: Raindrop integration for Pydantic AI — automatic observability for Agent run() and run_sync() calls
Author-email: Raindrop AI <sdk@raindrop.ai>
License-Expression: MIT
Project-URL: Homepage, https://raindrop.ai
Project-URL: Documentation, https://docs.raindrop.ai
Project-URL: Repository, https://github.com/invisible-tools/dawn/tree/main/packages/pydantic-ai-python
Keywords: raindrop,pydantic-ai,observability,llm,telemetry,ai
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: raindrop-ai>=0.0.42
Requires-Dist: pydantic-ai>=0.1.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: requests>=2.28; extra == "dev"
Dynamic: license-file

# raindrop-pydantic-ai

Raindrop integration for [Pydantic AI](https://ai.pydantic.dev/). Automatically captures Agent `run()` and `run_sync()` calls including input, output, model name, token usage, and finish reason.

[![PyPI version](https://img.shields.io/pypi/v/raindrop-pydantic-ai.svg)](https://pypi.org/project/raindrop-pydantic-ai/)
[![Python versions](https://img.shields.io/pypi/pyversions/raindrop-pydantic-ai.svg)](https://pypi.org/project/raindrop-pydantic-ai/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Installation

```bash
pip install raindrop-pydantic-ai pydantic-ai
```

## Quick Start

```python
from raindrop_pydantic_ai import RaindropPydanticAI
from pydantic_ai import Agent

raindrop = RaindropPydanticAI(
    api_key="your-write-key",
    user_id="user-123",
)

agent = Agent("openai:gpt-4o", system_prompt="Be helpful")
raindrop.wrap(agent)

result = agent.run_sync("What is the capital of France?")
print(result.output)

raindrop.flush()
```

### Async Usage

```python
import asyncio
from raindrop_pydantic_ai import RaindropPydanticAI
from pydantic_ai import Agent

raindrop = RaindropPydanticAI(api_key="rk_...", user_id="user-123")
agent = Agent("openai:gpt-4o")
raindrop.wrap(agent)

async def main():
    result = await agent.run("What is the capital of France?")
    print(result.output)
    raindrop.flush()

asyncio.run(main())
```

### Factory Function (Legacy)

The `create_raindrop_pydantic_ai()` factory function is still available for backwards compatibility:

```python
from raindrop_pydantic_ai import create_raindrop_pydantic_ai

raindrop = create_raindrop_pydantic_ai(api_key="rk_...", user_id="user-123")
```

## What Gets Captured

- **Agent runs**: input prompt, output text (including structured output), model name
- **Token usage**: `input_tokens` and `output_tokens` from the result
- **Finish reason**: `pydantic_ai.finish_reason` captured from the last model response (e.g. `"stop"`, `"length"`, `"tool_call"`)
- **Errors**: error type and message captured in event properties, then re-raised
- **Async support**: both `run()` (async) and `run_sync()` (sync) are instrumented
- **Double-wrap guard**: calling `wrap()` twice on the same agent is a safe no-op

## API Reference

### `RaindropPydanticAI(api_key, user_id=None, convo_id=None, tracing_enabled=True, bypass_otel_for_tools=True, debug=False)`

Create a new Raindrop wrapper instance.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `api_key` | `str \| None` | `None` | Raindrop API key. When `None` or empty, telemetry is disabled |
| `user_id` | `str \| None` | `None` | Associate all events with a user |
| `convo_id` | `str \| None` | `None` | Group events into a conversation |
| `tracing_enabled` | `bool` | `True` | Enable/disable tracing in `raindrop.init()` |
| `bypass_otel_for_tools` | `bool` | `True` | Bypass OpenTelemetry for tool calls |
| `debug` | `bool` | `False` | Enable DEBUG-level logging for the package |

### Debug Mode

```python
raindrop = RaindropPydanticAI(
    api_key="rk_...",
    debug=True,  # enables DEBUG-level logging
)
```

### `identify(user_id, traits=None)`

Identify a user with optional traits:

```python
raindrop.identify("user-123", traits={"name": "Alice", "plan": "pro", "age": 30})
```

### `track_signal(event_id, name, signal_type="default", ...)`

Track a signal event (feedback, edits, etc.):

```python
raindrop.track_signal(
    event_id="evt-abc",
    name="thumbs_up",
    signal_type="feedback",
    sentiment="POSITIVE",
    comment="Great answer!",
)
```

### `flush()` / `shutdown()`

Flush pending events before your process exits:

```python
raindrop.flush()     # flush pending data
raindrop.shutdown()  # flush + release resources
```

### Methods

| Method | Description |
|--------|-------------|
| `wrap(agent)` | Instrument a Pydantic AI Agent |
| `flush()` | Flush pending events to Raindrop |
| `shutdown()` | Flush and shut down the client |
| `identify(user_id, traits=None)` | Identify a user with optional traits |
| `track_signal(event_id, name, signal_type="default", ...)` | Track a custom signal event |

## Testing

```bash
cd packages/pydantic-ai-python
pip install -e ".[dev]"
python -m pytest tests/ -v
```

## Full Documentation

See [Raindrop Pydantic AI Integration Docs](https://docs.raindrop.ai/integrations/pydantic-ai) for full documentation.

## License

MIT
