@raindrop-ai/wizard 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +47 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +117 -0
- package/dist/bin.js.map +1 -0
- package/dist/src/docs/browser.md +105 -0
- package/dist/src/docs/python.md +618 -0
- package/dist/src/docs/typescript.md +584 -0
- package/dist/src/docs/vercel-ai-sdk.md +304 -0
- package/dist/src/lib/agent-interface.d.ts +46 -0
- package/dist/src/lib/agent-interface.js +292 -0
- package/dist/src/lib/agent-interface.js.map +1 -0
- package/dist/src/lib/agent-prompts.d.ts +10 -0
- package/dist/src/lib/agent-prompts.js +49 -0
- package/dist/src/lib/agent-prompts.js.map +1 -0
- package/dist/src/lib/config.d.ts +39 -0
- package/dist/src/lib/config.js +549 -0
- package/dist/src/lib/config.js.map +1 -0
- package/dist/src/lib/constants.d.ts +27 -0
- package/dist/src/lib/constants.js +165 -0
- package/dist/src/lib/constants.js.map +1 -0
- package/dist/src/lib/handlers.d.ts +68 -0
- package/dist/src/lib/handlers.js +420 -0
- package/dist/src/lib/handlers.js.map +1 -0
- package/dist/src/lib/integration-testing.d.ts +44 -0
- package/dist/src/lib/integration-testing.js +123 -0
- package/dist/src/lib/integration-testing.js.map +1 -0
- package/dist/src/lib/mcp.d.ts +14 -0
- package/dist/src/lib/mcp.js +134 -0
- package/dist/src/lib/mcp.js.map +1 -0
- package/dist/src/lib/sdk-messages.d.ts +17 -0
- package/dist/src/lib/sdk-messages.js +278 -0
- package/dist/src/lib/sdk-messages.js.map +1 -0
- package/dist/src/lib/wizard.d.ts +6 -0
- package/dist/src/lib/wizard.js +131 -0
- package/dist/src/lib/wizard.js.map +1 -0
- package/dist/src/run.d.ts +8 -0
- package/dist/src/run.js +53 -0
- package/dist/src/run.js.map +1 -0
- package/dist/src/ui/App.d.ts +15 -0
- package/dist/src/ui/App.js +27 -0
- package/dist/src/ui/App.js.map +1 -0
- package/dist/src/ui/cancellation.d.ts +14 -0
- package/dist/src/ui/cancellation.js +17 -0
- package/dist/src/ui/cancellation.js.map +1 -0
- package/dist/src/ui/components/ClarifyingQuestionsPrompt.d.ts +17 -0
- package/dist/src/ui/components/ClarifyingQuestionsPrompt.js +359 -0
- package/dist/src/ui/components/ClarifyingQuestionsPrompt.js.map +1 -0
- package/dist/src/ui/components/ContinuePrompt.d.ts +14 -0
- package/dist/src/ui/components/ContinuePrompt.js +23 -0
- package/dist/src/ui/components/ContinuePrompt.js.map +1 -0
- package/dist/src/ui/components/DiffDisplay.d.ts +18 -0
- package/dist/src/ui/components/DiffDisplay.js +110 -0
- package/dist/src/ui/components/DiffDisplay.js.map +1 -0
- package/dist/src/ui/components/FeedbackSelectPrompt.d.ts +20 -0
- package/dist/src/ui/components/FeedbackSelectPrompt.js +132 -0
- package/dist/src/ui/components/FeedbackSelectPrompt.js.map +1 -0
- package/dist/src/ui/components/HistoryItemDisplay.d.ts +14 -0
- package/dist/src/ui/components/HistoryItemDisplay.js +140 -0
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -0
- package/dist/src/ui/components/Logo.d.ts +10 -0
- package/dist/src/ui/components/Logo.js +47 -0
- package/dist/src/ui/components/Logo.js.map +1 -0
- package/dist/src/ui/components/OrgInfoBox.d.ts +11 -0
- package/dist/src/ui/components/OrgInfoBox.js +16 -0
- package/dist/src/ui/components/OrgInfoBox.js.map +1 -0
- package/dist/src/ui/components/PendingPrompt.d.ts +18 -0
- package/dist/src/ui/components/PendingPrompt.js +57 -0
- package/dist/src/ui/components/PendingPrompt.js.map +1 -0
- package/dist/src/ui/components/PersistentTextInput.d.ts +21 -0
- package/dist/src/ui/components/PersistentTextInput.js +117 -0
- package/dist/src/ui/components/PersistentTextInput.js.map +1 -0
- package/dist/src/ui/components/PlanApprovalPrompt.d.ts +19 -0
- package/dist/src/ui/components/PlanApprovalPrompt.js +62 -0
- package/dist/src/ui/components/PlanApprovalPrompt.js.map +1 -0
- package/dist/src/ui/components/PromptContainer.d.ts +14 -0
- package/dist/src/ui/components/PromptContainer.js +18 -0
- package/dist/src/ui/components/PromptContainer.js.map +1 -0
- package/dist/src/ui/components/SelectPrompt.d.ts +14 -0
- package/dist/src/ui/components/SelectPrompt.js +62 -0
- package/dist/src/ui/components/SelectPrompt.js.map +1 -0
- package/dist/src/ui/components/SpinnerDisplay.d.ts +13 -0
- package/dist/src/ui/components/SpinnerDisplay.js +11 -0
- package/dist/src/ui/components/SpinnerDisplay.js.map +1 -0
- package/dist/src/ui/components/ToolApprovalPrompt.d.ts +14 -0
- package/dist/src/ui/components/ToolApprovalPrompt.js +142 -0
- package/dist/src/ui/components/ToolApprovalPrompt.js.map +1 -0
- package/dist/src/ui/components/ToolCallDisplay.d.ts +14 -0
- package/dist/src/ui/components/ToolCallDisplay.js +83 -0
- package/dist/src/ui/components/ToolCallDisplay.js.map +1 -0
- package/dist/src/ui/components/WriteKeyDisplay.d.ts +15 -0
- package/dist/src/ui/components/WriteKeyDisplay.js +13 -0
- package/dist/src/ui/components/WriteKeyDisplay.js.map +1 -0
- package/dist/src/ui/contexts/WizardContext.d.ts +210 -0
- package/dist/src/ui/contexts/WizardContext.js +362 -0
- package/dist/src/ui/contexts/WizardContext.js.map +1 -0
- package/dist/src/ui/hooks/useCancellation.d.ts +15 -0
- package/dist/src/ui/hooks/useCancellation.js +25 -0
- package/dist/src/ui/hooks/useCancellation.js.map +1 -0
- package/dist/src/ui/render.d.ts +34 -0
- package/dist/src/ui/render.js +94 -0
- package/dist/src/ui/render.js.map +1 -0
- package/dist/src/ui/types.d.ts +184 -0
- package/dist/src/ui/types.js +6 -0
- package/dist/src/ui/types.js.map +1 -0
- package/dist/src/utils/clack-utils.d.ts +13 -0
- package/dist/src/utils/clack-utils.js +131 -0
- package/dist/src/utils/clack-utils.js.map +1 -0
- package/dist/src/utils/debug.d.ts +13 -0
- package/dist/src/utils/debug.js +47 -0
- package/dist/src/utils/debug.js.map +1 -0
- package/dist/src/utils/environment.d.ts +5 -0
- package/dist/src/utils/environment.js +131 -0
- package/dist/src/utils/environment.js.map +1 -0
- package/dist/src/utils/logging.d.ts +9 -0
- package/dist/src/utils/logging.js +38 -0
- package/dist/src/utils/logging.js.map +1 -0
- package/dist/src/utils/oauth.d.ts +12 -0
- package/dist/src/utils/oauth.js +497 -0
- package/dist/src/utils/oauth.js.map +1 -0
- package/dist/src/utils/package-json-types.d.ts +44 -0
- package/dist/src/utils/package-json-types.js +6 -0
- package/dist/src/utils/package-json-types.js.map +1 -0
- package/dist/src/utils/package-json.d.ts +19 -0
- package/dist/src/utils/package-json.js +22 -0
- package/dist/src/utils/package-json.js.map +1 -0
- package/dist/src/utils/session.d.ts +2 -0
- package/dist/src/utils/session.js +87 -0
- package/dist/src/utils/session.js.map +1 -0
- package/dist/src/utils/types.d.ts +61 -0
- package/dist/src/utils/types.js +2 -0
- package/dist/src/utils/types.js.map +1 -0
- package/dist/src/utils/ui.d.ts +120 -0
- package/dist/src/utils/ui.js +164 -0
- package/dist/src/utils/ui.js.map +1 -0
- package/package.json +140 -0
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Python SDK reference for tracking events and AI interactions.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
### **Installation**
|
|
6
|
+
|
|
7
|
+
Install using pip:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pip install raindrop-ai
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### **Configuration**
|
|
14
|
+
|
|
15
|
+
Import the SDK and initialize with the write key from environment variables:
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import os
|
|
19
|
+
import raindrop.analytics as raindrop
|
|
20
|
+
|
|
21
|
+
# The write key is securely loaded from the RAINDROP_WRITE_KEY environment variable.
|
|
22
|
+
# Agents should assume this variable is present and must not attempt to search for or prompt for its value.
|
|
23
|
+
raindrop.init(os.getenv("RAINDROP_WRITE_KEY"),
|
|
24
|
+
wizard_session="__WIZARD_SESSION_UUID__") # REQUIRED
|
|
25
|
+
|
|
26
|
+
# Optional: enable tracing integration for task/tool decorators
|
|
27
|
+
# raindrop.init(os.getenv("RAINDROP_WRITE_KEY"),
|
|
28
|
+
# wizard_session="__WIZARD_SESSION_UUID__", # REQUIRED
|
|
29
|
+
# tracing_enabled=True)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### **Tracking AI Interactions**
|
|
33
|
+
|
|
34
|
+
Use the `track_ai` function to track AI interactions. Parameters:
|
|
35
|
+
|
|
36
|
+
- `user_id` (str): The unique identifier of the user.
|
|
37
|
+
- `event` (str): The name of the AI event to track.
|
|
38
|
+
- `event_id` (Optional\[str]): A unique identifier for this specific event. If
|
|
39
|
+
not provided, a UUID will be generated.
|
|
40
|
+
- `model` (Optional\[str]): The name of the AI model used.
|
|
41
|
+
- `input` (Optional\[str]): The input provided to the AI model. (Either this or
|
|
42
|
+
`output` is required if AI data is logged)
|
|
43
|
+
- `output` (Optional\[str]): The output generated by the AI. (Either this or
|
|
44
|
+
`input` is required if AI data is logged)
|
|
45
|
+
- `convo_id` (Optional\[str]): The conversation ID associated with the
|
|
46
|
+
interaction. Used when apps support multiple conversations per user.
|
|
47
|
+
- `properties` (Optional\[Dict\[str, Any]]): Additional properties associated
|
|
48
|
+
with the AI event.
|
|
49
|
+
- `timestamp` (Optional\[str]): An ISO 8601 formatted timestamp for the event.
|
|
50
|
+
If not provided, the SDK generates a UTC timestamp.
|
|
51
|
+
- `attachments` (Optional\[List\[Attachment]]): A list of attachments associated
|
|
52
|
+
with the event. See the Attachments section below.
|
|
53
|
+
|
|
54
|
+
**Example usage:**
|
|
55
|
+
|
|
56
|
+
Note: `input` and `output` should be the actual prompt sent to and response
|
|
57
|
+
received from your AI model - not literal placeholder strings.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
raindrop.track_ai(
|
|
61
|
+
user_id=user_id, # The authenticated user's unique identifier from your app
|
|
62
|
+
event=event_name, # A descriptive name for this AI action (e.g. "chat_message", "code_generation")
|
|
63
|
+
model=model_name, # The model being called (e.g. "gpt-4o")
|
|
64
|
+
input=user_prompt, # The actual prompt sent to the model
|
|
65
|
+
output=model_response, # The actual response from the model
|
|
66
|
+
convo_id=convo_id, # Your app's conversation/thread ID (if applicable)
|
|
67
|
+
properties={ # Optional: any custom metadata relevant to your app
|
|
68
|
+
"system_prompt": system_prompt,
|
|
69
|
+
},
|
|
70
|
+
attachments=[
|
|
71
|
+
{
|
|
72
|
+
"type": "text",
|
|
73
|
+
"name": "Additional Info",
|
|
74
|
+
"value": "A very long document",
|
|
75
|
+
"role": "input",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "image",
|
|
79
|
+
"value": "https://example.com/image.png",
|
|
80
|
+
"role": "output",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"type": "iframe",
|
|
84
|
+
"name": "Generated UI",
|
|
85
|
+
"value": "https://newui.generated.com",
|
|
86
|
+
"role": "output",
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### **Attachments**
|
|
93
|
+
|
|
94
|
+
Attachments include additional context (images, documents, code, or embedded
|
|
95
|
+
content) as input or output. Each attachment has the following properties:
|
|
96
|
+
|
|
97
|
+
- `type` (string): The type of attachment. Can be "code", "text", "image", or
|
|
98
|
+
"iframe".
|
|
99
|
+
- `name` (optional string): A name for the attachment.
|
|
100
|
+
- `value` (string): The content or URL of the attachment.
|
|
101
|
+
- `role` (string): Either "input" or "output", indicating whether the attachment
|
|
102
|
+
is part of the user input or AI output.
|
|
103
|
+
- `language` (optional string): For code attachments, specifies the programming
|
|
104
|
+
language.
|
|
105
|
+
|
|
106
|
+
Example of different attachment types:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
attachments = [
|
|
110
|
+
{
|
|
111
|
+
"type": "code",
|
|
112
|
+
"name": "Example Code",
|
|
113
|
+
"value": "console.log('Hello, World!');",
|
|
114
|
+
"role": "input",
|
|
115
|
+
"language": "javascript",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"type": "text",
|
|
119
|
+
"name": "Additional Info",
|
|
120
|
+
"value": "Some extra text",
|
|
121
|
+
"role": "input",
|
|
122
|
+
},
|
|
123
|
+
{"type": "image", "value": "https://example.com/image.png", "role": "output"},
|
|
124
|
+
{"type": "iframe", "value": "https://example.com/embed", "role": "output"},
|
|
125
|
+
]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### **Identifying Users**
|
|
129
|
+
|
|
130
|
+
Use the `identify` function to associate traits with users. Parameters:
|
|
131
|
+
|
|
132
|
+
- `user_id` (str): The unique identifier of the user.
|
|
133
|
+
- `traits` (Dict\[str, Union\[str, int, bool, float]]): The traits associated
|
|
134
|
+
with the user.
|
|
135
|
+
|
|
136
|
+
**Example usage:**
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
# Pass actual user data from your app's auth/session
|
|
140
|
+
raindrop.identify(
|
|
141
|
+
user_id=user_id, # The authenticated user's unique identifier
|
|
142
|
+
traits={ # Pass any user traits available in your app — all keys are optional and freeform
|
|
143
|
+
"name": user_name,
|
|
144
|
+
"email": user_email,
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### **Partial Event Tracking (Interactions)**
|
|
150
|
+
|
|
151
|
+
For multi-turn conversations or when event data arrives incrementally, use
|
|
152
|
+
`begin()` and the `Interaction` object to send partial updates.
|
|
153
|
+
|
|
154
|
+
#### `begin()`
|
|
155
|
+
|
|
156
|
+
Starts or resumes an interaction and returns an `Interaction` helper object.
|
|
157
|
+
|
|
158
|
+
- `user_id` (str): The user's identifier.
|
|
159
|
+
- `event` (str): The name of the event.
|
|
160
|
+
- `event_id` (Optional\[str]): A unique ID for the event. If not provided, one
|
|
161
|
+
is generated.
|
|
162
|
+
- `properties` (Optional\[Dict\[str, Any]]): Initial properties for the event.
|
|
163
|
+
- `input` (Optional\[str]): Initial input for the AI.
|
|
164
|
+
- `attachments` (Optional\[List\[Attachment]]): Initial attachments.
|
|
165
|
+
- `convo_id` (Optional\[str]): Conversation ID.
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
interaction = raindrop.begin(
|
|
169
|
+
user_id=user_id, # The authenticated user's unique identifier from your app
|
|
170
|
+
event=event_name, # A descriptive name for this AI action
|
|
171
|
+
input=user_message # The actual user input
|
|
172
|
+
)
|
|
173
|
+
# interaction.id contains the event_id
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### `resume_interaction()`
|
|
177
|
+
|
|
178
|
+
If you already have an `event_id` for an ongoing interaction, you can get an
|
|
179
|
+
`Interaction` object:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
interaction = raindrop.resume_interaction(event_id=event_id) # The event ID from a previous begin() call
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `Interaction` Object Methods
|
|
186
|
+
|
|
187
|
+
The `Interaction` object has the following methods to update the event:
|
|
188
|
+
|
|
189
|
+
- `interaction.set_input(text: str)`: Updates the AI input.
|
|
190
|
+
- `interaction.add_attachments(attachments: List[Attachment])`: Adds more
|
|
191
|
+
attachments.
|
|
192
|
+
- `interaction.set_properties(props: Dict[str, Any])`: Merges new properties
|
|
193
|
+
with existing ones.
|
|
194
|
+
- `interaction.set_property(key: str, value: str)`: Convenience for setting a
|
|
195
|
+
single property.
|
|
196
|
+
- `interaction.finish(output: Optional[str] = None, **extra)`: Marks the
|
|
197
|
+
interaction as complete.
|
|
198
|
+
- `output`: The final AI output.
|
|
199
|
+
- `**extra`: Any other top-level `TrackAIEvent` fields to update (e.g.,
|
|
200
|
+
`properties`, `attachments`).
|
|
201
|
+
|
|
202
|
+
The SDK automatically sends updates to the backend after a short period of
|
|
203
|
+
inactivity or when `finish()` is called.
|
|
204
|
+
|
|
205
|
+
**Example usage:**
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
# Start an interaction — use actual values from your app
|
|
209
|
+
interaction = raindrop.begin(user_id=user_id, event=event_name, input=user_input)
|
|
210
|
+
|
|
211
|
+
# ... later, user adds more context
|
|
212
|
+
interaction.add_attachments([{"type": "text", "value": "It should be recursive", "role": "input"}])
|
|
213
|
+
|
|
214
|
+
# ... AI generates output
|
|
215
|
+
interaction.finish(output="def fib(n): if n <= 1: return n else: return fib(n-1) + fib(n-2)")
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### **Tracking Signals**
|
|
219
|
+
|
|
220
|
+
Signals are used to attach user feedback (such as thumbs down or thumbs up) or
|
|
221
|
+
other labels to existing events. Use the `track_signal` function:
|
|
222
|
+
|
|
223
|
+
- `event_id` (str): The ID of the event to attach the signal to.
|
|
224
|
+
- `name` (str): Name of the signal (e.g., "thumbs_up", "copied_code").
|
|
225
|
+
- `signal_type` (Literal\["default", "feedback", "edit"]): Type of signal.
|
|
226
|
+
Defaults to `"default"`.
|
|
227
|
+
- For `"feedback"` signals, a `"comment"` string must be included in the
|
|
228
|
+
`properties`.
|
|
229
|
+
- For `"edit"` signals, an `"after"` string (representing the content after
|
|
230
|
+
edit) must be included in the `properties`.
|
|
231
|
+
- `timestamp` (Optional\[str]): ISO 8601 formatted timestamp. Defaults to
|
|
232
|
+
current UTC time.
|
|
233
|
+
- `properties` (Optional\[Dict\[str, Any]]): Additional properties for the
|
|
234
|
+
signal.
|
|
235
|
+
- `attachment_id` (Optional\[str]): ID of a specific attachment within the
|
|
236
|
+
original event to associate this signal with.
|
|
237
|
+
- `sentiment` (Optional\[Literal\["POSITIVE", "NEGATIVE"]]): Optional sentiment
|
|
238
|
+
indicating whether the signal is positive or negative.
|
|
239
|
+
- `comment` (Optional\[str]): Convenience parameter for feedback signals. If
|
|
240
|
+
provided, it's added to `properties` as `{"comment": "your comment"}`.
|
|
241
|
+
- `after` (Optional\[str]): Convenience parameter for edit signals. If provided,
|
|
242
|
+
it's added to `properties` as `{"after": "new content"}`.
|
|
243
|
+
|
|
244
|
+
**Example usage:**
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
# Example: Tracking a thumbs-up signal
|
|
248
|
+
raindrop.track_signal(
|
|
249
|
+
event_id=event_id, # The ID of the AI event being rated (from begin() or track_ai())
|
|
250
|
+
name="thumbs_up",
|
|
251
|
+
signal_type="default",
|
|
252
|
+
sentiment="POSITIVE"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Example: Tracking a thumbs-down signal
|
|
256
|
+
raindrop.track_signal(
|
|
257
|
+
event_id=event_id, # The ID of the AI event being rated (from begin() or track_ai())
|
|
258
|
+
name="thumbs_down",
|
|
259
|
+
signal_type="default",
|
|
260
|
+
sentiment="NEGATIVE"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# Example: Tracking feedback
|
|
264
|
+
raindrop.track_signal(
|
|
265
|
+
event_id=event_id,
|
|
266
|
+
name="user_feedback",
|
|
267
|
+
signal_type="feedback",
|
|
268
|
+
comment=user_comment # The user's feedback comment
|
|
269
|
+
)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### **Timestamp**
|
|
273
|
+
|
|
274
|
+
Functions like `track_ai` and `track_signal` accept an optional `timestamp`
|
|
275
|
+
parameter (ISO 8601 formatted string) to specify a custom event time. If not
|
|
276
|
+
provided, the SDK generates a UTC timestamp at the moment of the call.
|
|
277
|
+
|
|
278
|
+
### **Flushing Events**
|
|
279
|
+
|
|
280
|
+
The Raindrop SDK uses a buffering mechanism to efficiently send events in
|
|
281
|
+
batches. The events are automatically flushed when the buffer reaches a certain
|
|
282
|
+
size or after a specified timeout.
|
|
283
|
+
|
|
284
|
+
You can manually flush the events by calling the `flush` function. Make sure
|
|
285
|
+
this happens before the process exits or you will lose events:
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
raindrop.flush()
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Shutting Down
|
|
292
|
+
|
|
293
|
+
To ensure all events are processed before your application exits, call the
|
|
294
|
+
shutdown function:
|
|
295
|
+
|
|
296
|
+
```python
|
|
297
|
+
raindrop.shutdown()
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
This will also flush any pending partial events from interactions.
|
|
301
|
+
|
|
302
|
+
### **Error Handling**
|
|
303
|
+
|
|
304
|
+
The SDK will retry a request up to 3 times. Failed requests will be logged,
|
|
305
|
+
regardless of if debug_logs is true.
|
|
306
|
+
|
|
307
|
+
### Configuration
|
|
308
|
+
|
|
309
|
+
The SDK has several configurable parameters:
|
|
310
|
+
|
|
311
|
+
- `max_queue_size`: Maximum number of events to store in the buffer (default:
|
|
312
|
+
10_000)
|
|
313
|
+
- `upload_size`: Number of events to send in a single API request (default: 10)
|
|
314
|
+
- `upload_interval`: Time interval in seconds between automatic flushes
|
|
315
|
+
(default: 1.0). You can modify these parameters if needed:
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
raindrop.max_queue_size = 20_000
|
|
319
|
+
raindrop.upload_size = 200
|
|
320
|
+
raindrop.upload_interval = 2.0
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### **Debugging**
|
|
324
|
+
|
|
325
|
+
To enable debug logs showing events being added to the buffer:
|
|
326
|
+
|
|
327
|
+
```python
|
|
328
|
+
raindrop.set_debug_logs(True)
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### **Tracing (Beta)**
|
|
332
|
+
|
|
333
|
+
1. Enable tracing by passing `tracing_enabled=True` to `raindrop.init(...)`.
|
|
334
|
+
2. Decorate the entry-point function with `@raindrop.interaction`.
|
|
335
|
+
3. Decorate tool functions with `@raindrop.tool`.
|
|
336
|
+
|
|
337
|
+
The example below traces OpenAI tool calls. It enables tracing, decorates a
|
|
338
|
+
tool, starts an interaction with `begin(...)`, and finishes it later via
|
|
339
|
+
`resume_interaction()`.
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
import json
|
|
343
|
+
import os
|
|
344
|
+
from openai import OpenAI
|
|
345
|
+
import raindrop.analytics as raindrop
|
|
346
|
+
|
|
347
|
+
@raindrop.tool("get_current_weather")
|
|
348
|
+
def get_current_weather(location: str, unit: str = "celsius"):
|
|
349
|
+
"""Mock weather tool."""
|
|
350
|
+
return {"location": location, "temperature": 22, "unit": unit}
|
|
351
|
+
|
|
352
|
+
def send_to_user(text: str) -> None:
|
|
353
|
+
# Resume the current interaction from the tracing context and finish elsewhere
|
|
354
|
+
# Pass the actual model response to output (not a placeholder string)
|
|
355
|
+
raindrop.resume_interaction().finish(output=text)
|
|
356
|
+
print(f"Sending to user: {text}")
|
|
357
|
+
|
|
358
|
+
@raindrop.interaction(interaction_name) # A descriptive name for this interaction flow
|
|
359
|
+
def main() -> None:
|
|
360
|
+
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
|
361
|
+
|
|
362
|
+
# Create an interaction for observability (begin → finish)
|
|
363
|
+
# Note: input should be the actual user prompt sent to the model
|
|
364
|
+
user_query = "What's the weather in Boston, MA today?"
|
|
365
|
+
interaction = raindrop.begin(
|
|
366
|
+
user_id=user_id, # The authenticated user's unique identifier from your app
|
|
367
|
+
event=event_name, # A descriptive name for this AI action
|
|
368
|
+
input=user_query, # Pass the actual user input
|
|
369
|
+
convo_id=convo_id, # Your app's conversation/thread ID (if applicable)
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
messages = [
|
|
373
|
+
{"role": "system", "content": "You are helpful. Use tools when needed."},
|
|
374
|
+
{"role": "user", "content": user_query},
|
|
375
|
+
]
|
|
376
|
+
|
|
377
|
+
# Let the model request tool invocations if needed
|
|
378
|
+
first = client.chat.completions.create(
|
|
379
|
+
model="gpt-4o-mini",
|
|
380
|
+
messages=messages,
|
|
381
|
+
tools=[{
|
|
382
|
+
"type": "function",
|
|
383
|
+
"function": {
|
|
384
|
+
"name": "get_current_weather",
|
|
385
|
+
"parameters": {
|
|
386
|
+
"type": "object",
|
|
387
|
+
"properties": {
|
|
388
|
+
"location": {"type": "string"},
|
|
389
|
+
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
|
|
390
|
+
},
|
|
391
|
+
"required": ["location"],
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
}],
|
|
395
|
+
tool_choice="auto",
|
|
396
|
+
temperature=0.2,
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
choice = first.choices[0]
|
|
400
|
+
tool_calls = getattr(choice.message, "tool_calls", None)
|
|
401
|
+
|
|
402
|
+
if tool_calls:
|
|
403
|
+
messages.append({
|
|
404
|
+
"role": "assistant",
|
|
405
|
+
"content": getattr(choice.message, "content", None),
|
|
406
|
+
"tool_calls": [{
|
|
407
|
+
"id": tc.id,
|
|
408
|
+
"type": "function",
|
|
409
|
+
"function": {"name": tc.function.name, "arguments": tc.function.arguments},
|
|
410
|
+
} for tc in tool_calls],
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
for tc in tool_calls:
|
|
414
|
+
args = json.loads(tc.function.arguments or "{}")
|
|
415
|
+
result = (
|
|
416
|
+
get_current_weather(**args)
|
|
417
|
+
if tc.function.name == "get_current_weather"
|
|
418
|
+
else {"error": "unknown tool"}
|
|
419
|
+
)
|
|
420
|
+
messages.append({
|
|
421
|
+
"role": "tool",
|
|
422
|
+
"tool_call_id": tc.id,
|
|
423
|
+
"name": tc.function.name,
|
|
424
|
+
"content": json.dumps(result),
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
# Final model response after tools
|
|
428
|
+
second = client.chat.completions.create(
|
|
429
|
+
model="gpt-4o-mini", messages=messages, temperature=0.2
|
|
430
|
+
)
|
|
431
|
+
final_text = second.choices[0].message.content or ""
|
|
432
|
+
else:
|
|
433
|
+
final_text = choice.message.content or ""
|
|
434
|
+
|
|
435
|
+
print("Assistant:\n", final_text)
|
|
436
|
+
send_to_user(final_text)
|
|
437
|
+
raindrop.flush()
|
|
438
|
+
raindrop.shutdown()
|
|
439
|
+
|
|
440
|
+
if __name__ == "__main__":
|
|
441
|
+
raindrop.init(os.getenv("RAINDROP_WRITE_KEY"),
|
|
442
|
+
wizard_session="__WIZARD_SESSION_UUID__", # REQUIRED
|
|
443
|
+
tracing_enabled=True)
|
|
444
|
+
main()
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
#### Using the `@raindrop.interaction()` decorator (Beta)
|
|
448
|
+
|
|
449
|
+
You can wrap your flow with the `@raindrop.interaction("name")` decorator to
|
|
450
|
+
ensure a tracing context exists, which allows `resume_interaction()` to find the
|
|
451
|
+
current Interaction without passing an `event_id`:
|
|
452
|
+
|
|
453
|
+
```python
|
|
454
|
+
import os
|
|
455
|
+
import raindrop.analytics as raindrop
|
|
456
|
+
|
|
457
|
+
raindrop.init(os.getenv("RAINDROP_WRITE_KEY"),
|
|
458
|
+
wizard_session="__WIZARD_SESSION_UUID__", # REQUIRED
|
|
459
|
+
tracing_enabled=True)
|
|
460
|
+
|
|
461
|
+
def send_to_user():
|
|
462
|
+
interaction = raindrop.resume_interaction()
|
|
463
|
+
interaction.finish(output=model_response) # The actual model response
|
|
464
|
+
|
|
465
|
+
@raindrop.interaction(interaction_name) # A descriptive name for this interaction flow
|
|
466
|
+
def run_weather_flow():
|
|
467
|
+
interaction = raindrop.begin(user_id=user_id, event=event_name, input=user_query)
|
|
468
|
+
send_to_user()
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
run_weather_flow()
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
<Note>
|
|
475
|
+
<strong>Resume caveats:</strong>
|
|
476
|
+
- `resume_interaction()` resolves the current Interaction by reading the active tracing context (current span). It will only find an existing Interaction when called under the same traced execution that called `begin(...)` (for example, inside a function decorated with `@raindrop.task`, `@raindrop.tool`, or `@raindrop.interaction`).
|
|
477
|
+
- If your code runs outside that tracing context (separate thread/process, lost OpenTelemetry context, background job, etc.), pass the event ID explicitly: `resume_interaction(event_id="...")`.
|
|
478
|
+
- If neither a matching trace context nor an `event_id` is available, a new `Interaction` instance will be created.
|
|
479
|
+
</Note>
|
|
480
|
+
|
|
481
|
+
#### Using the `tool_span` and `task_span` context managers (Beta)
|
|
482
|
+
|
|
483
|
+
When decorators aren't feasible (e.g., dynamic tool selection, complex control
|
|
484
|
+
flow), you can use context managers for fine-grained tracing control.
|
|
485
|
+
|
|
486
|
+
**Requirements:**
|
|
487
|
+
|
|
488
|
+
1. Initialize with `tracing_enabled=True`
|
|
489
|
+
2. Decorate your entry-point function with `@raindrop.interaction` to establish
|
|
490
|
+
a tracing context
|
|
491
|
+
3. Use `with raindrop.tool_span(...)` or `with raindrop.task_span(...)` for
|
|
492
|
+
traced blocks
|
|
493
|
+
|
|
494
|
+
Context managers support both synchronous and asynchronous code. Spans
|
|
495
|
+
automatically inherit the current trace context and no-op when tracing is
|
|
496
|
+
disabled.
|
|
497
|
+
|
|
498
|
+
**Available methods on the span object:**
|
|
499
|
+
|
|
500
|
+
- `record_input(data)`: Record input data for the span
|
|
501
|
+
- `record_output(data)`: Record output data for the span
|
|
502
|
+
- `set_properties(props)`: Set custom properties on the span
|
|
503
|
+
|
|
504
|
+
**Example:**
|
|
505
|
+
|
|
506
|
+
```python
|
|
507
|
+
import asyncio
|
|
508
|
+
import os
|
|
509
|
+
import raindrop.analytics as raindrop
|
|
510
|
+
import time
|
|
511
|
+
|
|
512
|
+
raindrop.init(os.getenv("RAINDROP_WRITE_KEY"),
|
|
513
|
+
wizard_session="__WIZARD_SESSION_UUID__", # REQUIRED
|
|
514
|
+
tracing_enabled=True)
|
|
515
|
+
|
|
516
|
+
@raindrop.task(task_name) # A descriptive name for this task
|
|
517
|
+
async def main():
|
|
518
|
+
interaction = raindrop.begin(
|
|
519
|
+
user_id=user_id, # The authenticated user's unique identifier from your app
|
|
520
|
+
event=event_name, # A descriptive name for this AI action
|
|
521
|
+
input=user_query # Pass the actual user input
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
# Synchronous tool call: web_search
|
|
525
|
+
with raindrop.tool_span("web_search", version=1) as tool:
|
|
526
|
+
tool.record_input({"query": user_query}) # Pass actual tool call param value
|
|
527
|
+
time.sleep(0.1) # Simulate API call
|
|
528
|
+
search_results = ["https://docs.example.com/api", "https://blog.example.com/tutorial"]
|
|
529
|
+
tool.set_properties({"results_count": len(search_results)})
|
|
530
|
+
tool.record_output({"urls": search_results})
|
|
531
|
+
|
|
532
|
+
# Async tool call: document_reranker
|
|
533
|
+
async with raindrop.tool_span("document_reranker") as tool:
|
|
534
|
+
tool.record_input({
|
|
535
|
+
"documents": search_results,
|
|
536
|
+
"query": user_query
|
|
537
|
+
})
|
|
538
|
+
await asyncio.sleep(0.05) # Simulate async reranking
|
|
539
|
+
best_doc = search_results[0]
|
|
540
|
+
tool.record_output({"top_document": best_doc})
|
|
541
|
+
|
|
542
|
+
# Nested task span for summarization
|
|
543
|
+
with raindrop.task_span("summarization") as task:
|
|
544
|
+
task.record_input({"document": best_doc})
|
|
545
|
+
summary = call_summarization_model(best_doc)
|
|
546
|
+
task.record_output({"summary": summary})
|
|
547
|
+
|
|
548
|
+
interaction.finish(output=summary) # Pass actual model response
|
|
549
|
+
raindrop.shutdown()
|
|
550
|
+
|
|
551
|
+
if __name__ == "__main__":
|
|
552
|
+
asyncio.run(main())
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
#### Using `interaction.start_span()` for Manual Spans (Beta)
|
|
556
|
+
|
|
557
|
+
When the span lifecycle doesn't fit within a `with` block (e.g., the span starts
|
|
558
|
+
in one function and ends in another), use `interaction.start_span()` to create a
|
|
559
|
+
`ManualSpan` with an explicit `.end()` call.
|
|
560
|
+
|
|
561
|
+
```python
|
|
562
|
+
span = interaction.start_span(kind="tool", name="my_tool")
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
**Parameters:**
|
|
566
|
+
|
|
567
|
+
- `kind` (Literal["task", "tool"]): The type of span.
|
|
568
|
+
- `name` (str): Name of the span.
|
|
569
|
+
- `version` (Optional[int]): Version number for the span.
|
|
570
|
+
|
|
571
|
+
**`ManualSpan` methods:**
|
|
572
|
+
|
|
573
|
+
- `record_input(data)`: Record input data for the span.
|
|
574
|
+
- `record_output(data)`: Record output data for the span.
|
|
575
|
+
- `set_properties(props)`: Set custom properties on the span.
|
|
576
|
+
- `end(error=None)`: End the span. Pass an exception to mark it as failed.
|
|
577
|
+
|
|
578
|
+
**`ManualSpan` properties:**
|
|
579
|
+
|
|
580
|
+
- `event_id`: The interaction's event_id.
|
|
581
|
+
|
|
582
|
+
The span automatically inherits association properties (`event_id`, `user_id`,
|
|
583
|
+
`event`, `convo_id`) from the interaction.
|
|
584
|
+
|
|
585
|
+
**Example:**
|
|
586
|
+
|
|
587
|
+
```python
|
|
588
|
+
import os
|
|
589
|
+
import raindrop.analytics as raindrop
|
|
590
|
+
|
|
591
|
+
raindrop.init(os.getenv("RAINDROP_WRITE_KEY"),
|
|
592
|
+
wizard_session="__WIZARD_SESSION_UUID__", # REQUIRED
|
|
593
|
+
tracing_enabled=True)
|
|
594
|
+
|
|
595
|
+
@raindrop.interaction(interaction_name) # A descriptive name for this interaction flow
|
|
596
|
+
def main():
|
|
597
|
+
user_input = get_user_input() # Your actual user input
|
|
598
|
+
interaction = raindrop.begin(user_id=user_id, event=event_name, input=user_input)
|
|
599
|
+
|
|
600
|
+
# Start a span
|
|
601
|
+
span = interaction.start_span(kind="tool", name="external_api")
|
|
602
|
+
span.record_input({"query": api_query}) # Pass actual query data
|
|
603
|
+
|
|
604
|
+
try:
|
|
605
|
+
result = call_external_api()
|
|
606
|
+
span.record_output(result)
|
|
607
|
+
span.end()
|
|
608
|
+
except Exception as e:
|
|
609
|
+
span.end(error=e)
|
|
610
|
+
|
|
611
|
+
interaction.finish(output=final_response) # Pass actual model response
|
|
612
|
+
raindrop.shutdown()
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### **Troubleshooting**
|
|
616
|
+
|
|
617
|
+
- Each event has a limit of 1 MB. Properties will be truncated for larger
|
|
618
|
+
events.
|