raindrop-dspy
Raindrop observability integration for DSPy. Wraps DSPy modules (Predict, ChainOfThought, etc.) to automatically capture input fields, output fields, model name, and token usage.
Installation
pip install raindrop-dspy dspy
Quick Start
import dspy
from raindrop_dspy import RaindropDSPy
raindrop = RaindropDSPy(api_key="rk_...", user_id="user-123")
lm = dspy.LM("openai/gpt-4o-mini")
dspy.configure(lm=lm)
predict = dspy.Predict("question -> answer")
wrapped = raindrop.wrap(predict)
result = wrapped(question="What is the capital of France?")
print(result.answer)
raindrop.shutdown()
Projects
Route events to a specific project by passing its slug as project_id:
raindrop = RaindropDSPy(
api_key="rk_...",
project_id="support-prod",
)
project_id sets the X-Raindrop-Project-Id header on every event. Omit it (or pass "default") to use your org's default Production project, which is the existing behavior. The same option is accepted by the create_raindrop_dspy(...) factory. Invalid slugs are ignored with a warning and no header is sent.
Debug Mode
Enable verbose logging to troubleshoot issues:
raindrop = RaindropDSPy(api_key="rk_...", debug=True)
Factory Function (Legacy)
The create_raindrop_dspy factory function is still available for backwards compatibility:
from raindrop_dspy import create_raindrop_dspy
raindrop = create_raindrop_dspy(
api_key="rk_...",
user_id="user-123",
tracing_enabled=True,
bypass_otel_for_tools=True,
)
wrapped = raindrop.wrap(predict)
What Gets Captured
| Data | Description |
|---|---|
| Input fields | All keyword arguments passed to forward() |
| Output fields | Extracted from the DSPy Prediction result |
| Model name | From the active dspy.settings.lm configuration |
| Token usage | Prompt and completion tokens (when available) |
| Errors | Exception type and message captured in event properties |
| Finish reason | Completion finish reason (e.g. stop, length) from the LM history |
API Reference
RaindropDSPy(api_key=None, user_id=None, convo_id=None, project_id=None, tracing_enabled=True, bypass_otel_for_tools=True, disable_auto_instrument=True, debug=False)
Create a new Raindrop DSPy integration instance.
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str | None |
None |
Raindrop API key. If omitted, telemetry is disabled. |
user_id |
str | None |
None |
Associate all events with a user |
convo_id |
str | None |
None |
Group events into a conversation |
project_id |
str | None |
None |
Route events to a specific project (slug); omit for the default Production project |
tracing_enabled |
bool |
True |
Enable OpenTelemetry tracing |
bypass_otel_for_tools |
bool |
True |
Bypass OTEL instrumentation for tool calls |
disable_auto_instrument |
bool |
True |
Library auto-instrumentation is opt-in (see below) |
debug |
bool |
False |
Enable debug logging (sets logger to DEBUG level) |
Library auto-instrumentation is opt-in
As of 0.0.4, disable_auto_instrument defaults to True: the
integration no longer lets Traceloop monkey-patch every LLM client library
it recognizes in your process (including the OpenAI client DSPy drives through LiteLLM). The
wrapper captures input/output, token usage, and model name
directly from the wrapped module's forward() calls and DSPy LM history, so no library patching is needed for full
dashboards.
If you specifically want LLM-call-level spans from library instrumentation
and have verified compatibility in your environment, opt back in with
disable_auto_instrument=False.
Methods
| Method | Description |
|---|---|
wrap(module) |
Instrument a DSPy module (sync and async forward supported) |
flush() |
Flush buffered 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 signal on an AI event (e.g. thumbs up/down, feedback) |
Identifying Users
raindrop.identify("user-123", traits={"name": "Alice", "plan": "pro"})
Tracking Signals
raindrop.track_signal(
event_id="evt-abc",
name="thumbs_up",
signal_type="feedback",
sentiment="POSITIVE",
comment="Great response!",
)
Flushing and Shutdown
raindrop.flush() # flush pending data
raindrop.shutdown() # flush + release resources
Async Support
DSPy modules with async forward methods are automatically detected and wrapped:
import dspy
from raindrop_dspy import RaindropDSPy
raindrop = RaindropDSPy(api_key="rk_...")
class AsyncPredict(dspy.Module):
async def forward(self, question: str) -> dspy.Prediction:
...
wrapped = raindrop.wrap(AsyncPredict())
result = await wrapped(question="Hello")
Double-Wrap Protection
Calling wrap() on an already-wrapped module is a no-op — the module is returned unchanged.
Application Git metadata
RaindropDSPy(...) and create_raindrop_dspy(...) accept the keyword-only app_git option. It defaults to True: explicit Raindrop Git environment or deployment context is applied immediately, and the base SDK may perform one bounded background local-Git lookup from the process working directory. Event capture, flush, and shutdown never wait for that lookup. Pass False to disable enrichment, or pass an AppGitOptions mapping with commit_sha, commit_dirty, branch, source_directory, detect_branch, and/or auto_detect. Automatic branch discovery remains opt-in through detect_branch=True (or RAINDROP_GIT_DETECT_BRANCH=true).
For an ordinary in-process application, the process working directory is treated as the application-under-test checkout. A remote, coding, workflow, or observer process must not rely on its own checkout: pass app_git=False, provide explicit revision values, or set source_directory to the actual application checkout. Canonical per-operation properties remain authoritative. When supplying client=, configure app_git while constructing that Raindrop client; the supplied client is authoritative and the wrapper's app_git argument does not reconfigure it.
Release order is deliberate: first publish the base SDK feature, then publish the wrapper feature release with its minimum dependency coordinated to that base release. The existing raindrop-ai lower bound remains compatible, but application Git metadata is unavailable on an older core and must not be claimed complete until the base is upgraded. Until coordination assigns a released version, the wrapper checks for an explicit base app_git parameter and omits the option when unsupported. Explicit non-default configuration is debug-logged and omitted. Unsupported app_git is determined by signature inspection before construction, not by retrying initialization after a TypeError; Git configuration adds no initialization attempts and does not change any existing framework-specific initialization fallback.
Development
cd packages/dspy-python
pip install -e ".[dev]"
python -m pytest tests/ -v # unit tests (no external services)
End-to-end behavior is verified by the cross-SDK conformance harness. This
package ships a thin conformance driver at
conformance/driver.py that maps the shared scenario
corpus onto the wrapper's public API; known gaps are tracked as ticket-linked
entries in conformance/failures.txt. The fault
lane runs on every PR touching packages/*-python/**
(.github/workflows/conformance-wrappers-python.yml) against a local capture
server; the prod lane verifies delivery by reading back through the public
Query API. The harness is
pinned by commit SHA (HARNESS_REF). See the harness docs:
HOW-IT-WORKS ·
AGENTS ·
README.
License
MIT
Metadata
Release files for raindrop-dspy 0.0.10
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| raindrop_dspy-0.0.10.tar.gz | 30.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| raindrop_dspy-0.0.10-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.4 kB
Release files / raindrop_dspy-0.0.10.tar.gz
| Download URL | raindrop_dspy-0.0.10.tar.gz |
|---|---|
| Size | 30.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ed931c3ae7e26cfe166854ce487d4f315c0f9965fb40db7d42878c18267ab601
|
|
BLAKE2b-256 checksum How to use checksums |
a8ba40755d0540d6fe81288fc4456fa4257f8adce5972b1cd9114dc6fbd0f609
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / raindrop_dspy-0.0.10-py3-none-any.whl
| Download URL | raindrop_dspy-0.0.10-py3-none-any.whl |
|---|---|
| Size | 14.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2d367134ec06adfdc00689a37ef5a19068ca5b1608bb4a981fb93621430ff39f
|
|
BLAKE2b-256 checksum How to use checksums |
6b1e361531f2965df287298aaecd6510c3aa8c026bd9ae410c663804aa0b49ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|