Skip to main content

Installation

Quick Start

What Gets Traced

The DSPy integration automatically captures:
  • Module calls — input kwargs, output text (from Prediction result), configured model name
  • Token usage — prompt and completion tokens from get_lm_usage() or the usage attribute
  • Finish reason — completion finish reason (e.g. stop, length) extracted from the LM history
  • Errors — exception type and message captured in event properties, then re-raised
Works with dspy.Predict, dspy.ChainOfThought, and custom dspy.Module subclasses.

Configuration

Projects

Route events to a specific project by passing its slug as project_id:
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.

Multiple projects in one process

Available in raindrop-ai>=0.0.56. When one service runs several DSPy modules that should report to different projects, create one RaindropDSPy wrapper per project. Each wrapper owns its own raindrop.Raindrop client, so the two route independently — there is no shared module-level state:
Each wrapper owns its configuration and delivery pipeline, so modules handled by different wrappers route independently. To share a single client across wrappers (or with the module-level API), construct a raindrop.Raindrop yourself and pass it via client=:

Identifying Users

Use identify() to associate a user with traits after initialization:
The traits parameter accepts a dictionary with string, int, bool, or float values.

Tracking Signals

Use track_signal() to attach user feedback or edits to an AI event:

Tool catalog capture (ai.prompt.tools)

raindrop-dspy ≥ 0.0.11 reads the list from DSPy’s own callback hook: while a wrapped module’s forward() runs, the wrapper installs a callback through dspy.context(callbacks=...) whose on_lm_start receives the LM call’s kwargs["tools"], the native tool list ChatAdapter(use_native_function_calling=True) built for that request, and binds it until on_lm_end. Every litellm.chat span started in between records ai.prompt.tools with the JSON Schema as given. Capture is exact, per LM call; an LM call without native tools (the default adapter describes tools in the prompt text instead) records []. Model spans come from the OpenLLMetry litellm instrumentation, which only runs with disable_auto_instrument=False; with the default True there is no model span at all. The instrumentation writes the same list to gen_ai.tool.definitions (OpenLLMetry ≥ 0.62 no longer emits llm.request.functions.*), which raindrop-ai ≥ 0.0.72 also rebuilds from; the wrapper does not depend on that, and its bound list takes precedence when both are present. wrap() instruments forward (sync or async def forward); LM calls made through acall() / aforward() bypass it, so no override reaches them: with raindrop-ai ≥ 0.0.72 they carry the exact request list the core rebuilds, on 0.0.70 / 0.0.71 they carry no attribute. Pass tools= on RaindropDSPy(...) / create_raindrop_dspy(...) as the default for every LM call, or wrap(module, tools=[...]) for one module; an override is bound for the whole forward() call, the per-wrap value replaces the default, either replaces the inferred list, and tools=[] records an empty catalog. Follows TRACELOOP_TRACE_CONTENT; needs raindrop-ai ≥ 0.0.70. See Tool catalog capture for the attribute format, the absent / [] semantics and the override shapes accepted.

Flushing and Shutdown

Always call shutdown() before your process exits to ensure all telemetry is shipped:

Finish Reason Tracking

The integration extracts finish_reason from the DSPy LM history automatically. After each call, it inspects dspy.settings.lm.history for the last response and reads response.choices[0].finish_reason. The value (e.g. stop, length) is included in event properties as dspy.finish_reason.

Token Tracking

Token usage is extracted from the DSPy Prediction result:
  1. get_lm_usage() — returns {model: {prompt_tokens, completion_tokens}}. Tokens are summed across models if multiple LMs are used.
  2. usage attribute — fallback for older DSPy versions. Supports both dict and object formats.
Tokens appear in event properties as ai.usage.prompt_tokens and ai.usage.completion_tokens.

Factory Function

The create_raindrop_dspy factory function is available for backwards compatibility:

Async Support

DSPy modules with async forward methods are automatically detected and wrapped:

Application Git metadata (Python)

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.

Captured Properties

Each event includes the following properties when available: