Installation
pip install raindrop-pydantic-ai pydantic-ai
Quick Start
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()
What Gets Traced
The Pydantic AI integration automatically captures:
- Agent runs — input prompt, output text (including structured Pydantic model output), model name
- Token usage — input_tokens and output_tokens from the agent result
- Finish reason —
pydantic_ai.finish_reasoncaptured from the last model response (e.g. "stop", "length", "tool_call") - Errors — error type and message captured in event properties, then re-raised to the caller
- Async support — both
run()(async) andrun_sync()(sync) are instrumented - Double-wrap guard — calling
wrap()twice on the same agent is a safe no-op
Configuration
raindrop = RaindropPydanticAI(
api_key="your-write-key", # Raindrop API key (None = disabled mode)
user_id="user-123", # Optional: associate events with a user
convo_id="convo-456", # Optional: conversation/thread ID
tracing_enabled=True, # Optional: enable/disable tracing
bypass_otel_for_tools=True, # Optional: bypass OTEL for tool calls
debug=True, # Optional: enable DEBUG-level logging
)
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
`str | None` | None |
user_id |
`str | None` | None |
convo_id |
`str | None` | None |
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 |
Structured Output
The integration handles Pydantic AI’s structured output types — the output is serialized to JSON for telemetry:
from pydantic import BaseModel
class CityInfo(BaseModel):
name: str
country: str
population: int
agent = Agent("openai:gpt-4o", output_type=CityInfo)
raindrop.wrap(agent)
result = agent.run_sync("Tell me about Paris")
print(result.output) # CityInfo(name='Paris', country='France', population=2161000)
raindrop.flush()
Async Usage
The wrapper supports both sync and async agent runs:
import asyncio
async def main():
result = await agent.run("What is quantum computing?")
print(result.output)
raindrop.flush()
asyncio.run(main())
Identifying Users
Use identify() to associate a user with traits:
raindrop.identify("user-123", traits={
"name": "Alice",
"plan": "pro",
"age": 30,
"active": True,
})
Traits values must be str, int, bool, or float.
Tracking Signals
Use track_signal() to record feedback, edits, or custom signals:
# Feedback signal
raindrop.track_signal(
event_id="evt-abc",
name="thumbs_up",
signal_type="feedback",
sentiment="POSITIVE",
comment="Great answer!",
)
# Edit signal
raindrop.track_signal(
event_id="evt-abc",
name="user_edit",
signal_type="edit",
after="The corrected answer is ...",
)
| Parameter | Type | Default | Description |
|---|---|---|---|
event_id |
str |
required | The event ID to attach the signal to |
name |
str |
required | Signal name |
signal_type |
`"default" | "feedback" | "edit"` |
timestamp |
`str | None` | None |
properties |
`dict | None` | None |
attachment_id |
`str | None` | None |
comment |
`str | None` | None |
after |
`str | None` | None |
sentiment |
`"POSITIVE" | "NEGATIVE" | None` |
Flushing and Shutdown
Always call flush() before your process exits to ensure all telemetry is shipped:
raindrop.flush() # flush pending data
raindrop.shutdown() # flush + release resources
Factory Function (Legacy)
The create_raindrop_pydantic_ai() factory is available for backwards compatibility:
from raindrop_pydantic_ai import create_raindrop_pydantic_ai
raindrop = create_raindrop_pydantic_ai(
api_key="rk_...",
user_id="user-123",
tracing_enabled=True,
bypass_otel_for_tools=True,
)
Known Limitations
run_stream()is not instrumented — onlyrun()andrun_sync()are captured. Streaming runs produce no telemetry.- Multi-step agent runs: In agents with multiple LLM calls (e.g., tool use loops), only the final result’s data is captured. Intermediate LLM calls are not tracked individually.