driftrail 2.0.0__py3-none-any.whl → 2.1.0__py3-none-any.whl
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.
- driftrail/__init__.py +190 -6
- driftrail/client.py +501 -313
- driftrail/types.py +642 -1
- driftrail-2.1.0.dist-info/METADATA +469 -0
- driftrail-2.1.0.dist-info/RECORD +9 -0
- driftrail-2.0.0.dist-info/METADATA +0 -226
- driftrail-2.0.0.dist-info/RECORD +0 -9
- {driftrail-2.0.0.dist-info → driftrail-2.1.0.dist-info}/WHEEL +0 -0
- {driftrail-2.0.0.dist-info → driftrail-2.1.0.dist-info}/licenses/LICENSE +0 -0
- {driftrail-2.0.0.dist-info → driftrail-2.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: driftrail
|
|
3
|
+
Version: 2.1.0
|
|
4
|
+
Summary: DriftRail SDK - Complete AI Safety & Observability Platform with enterprise features for LLM monitoring, guardrails, drift detection, tracing, evaluations, and compliance
|
|
5
|
+
Author-email: DriftRail <support@driftrail.com>
|
|
6
|
+
Maintainer-email: DriftRail <support@driftrail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://driftrail.com
|
|
9
|
+
Project-URL: Documentation, https://docs.driftrail.com
|
|
10
|
+
Project-URL: Repository, https://github.com/cutmob/DriftRail-Python
|
|
11
|
+
Project-URL: Changelog, https://github.com/cutmob/DriftRail-Python/blob/main/CHANGELOG.md
|
|
12
|
+
Project-URL: Bug Tracker, https://github.com/cutmob/DriftRail-Python/issues
|
|
13
|
+
Keywords: ai,llm,observability,safety,monitoring,audit,guardrails,compliance,openai,anthropic,gemini,machine-learning,mlops
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
27
|
+
Classifier: Topic :: System :: Monitoring
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.8
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Provides-Extra: async
|
|
33
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "async"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
37
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# DriftRail Python SDK
|
|
42
|
+
|
|
43
|
+
Official Python SDK for [DriftRail](https://driftrail.com) - AI Safety & Observability Platform.
|
|
44
|
+
|
|
45
|
+
[](https://badge.fury.io/py/driftrail)
|
|
46
|
+
[](https://www.python.org/downloads/)
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install driftrail
|
|
52
|
+
|
|
53
|
+
# With async support
|
|
54
|
+
pip install driftrail[async]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from driftrail import DriftRail
|
|
61
|
+
|
|
62
|
+
client = DriftRail(
|
|
63
|
+
api_key="dr_live_...",
|
|
64
|
+
app_id="my-app"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Log an LLM interaction
|
|
68
|
+
response = client.ingest(
|
|
69
|
+
model="gpt-4o",
|
|
70
|
+
provider="openai",
|
|
71
|
+
input={"prompt": "What is the capital of France?"},
|
|
72
|
+
output={"text": "The capital of France is Paris."},
|
|
73
|
+
metadata={"latency_ms": 250, "tokens_in": 10, "tokens_out": 8}
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
print(f"Event ID: {response.event_id}")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Inline Guardrails
|
|
80
|
+
|
|
81
|
+
Block dangerous outputs before they reach users:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
result = client.guard(
|
|
85
|
+
output=llm_response,
|
|
86
|
+
input=user_prompt,
|
|
87
|
+
mode="strict" # or "permissive"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if result.allowed:
|
|
91
|
+
return result.output # May be redacted
|
|
92
|
+
else:
|
|
93
|
+
return "Sorry, I can't help with that."
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Async Client
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from driftrail import DriftRailAsync
|
|
100
|
+
|
|
101
|
+
async with DriftRailAsync(api_key="...", app_id="my-app") as client:
|
|
102
|
+
response = await client.ingest(
|
|
103
|
+
model="gpt-4o",
|
|
104
|
+
provider="openai",
|
|
105
|
+
input={"prompt": "Hello"},
|
|
106
|
+
output={"text": "Hi there!"}
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Enterprise Features
|
|
111
|
+
|
|
112
|
+
The `DriftRailEnterprise` client provides access to all dashboard features:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from driftrail import DriftRailEnterprise
|
|
116
|
+
|
|
117
|
+
client = DriftRailEnterprise(api_key="dr_live_...", app_id="my-app")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Incidents
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# List incidents
|
|
124
|
+
incidents = client.list_incidents(
|
|
125
|
+
status=["open", "investigating"],
|
|
126
|
+
severity=["high", "critical"]
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Create incident
|
|
130
|
+
incident = client.create_incident(
|
|
131
|
+
title="High risk outputs detected",
|
|
132
|
+
severity="high",
|
|
133
|
+
incident_type="safety",
|
|
134
|
+
description="Multiple high-risk outputs in production"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Get stats
|
|
138
|
+
stats = client.get_incident_stats()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Compliance
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
# Get compliance status
|
|
145
|
+
status = client.get_compliance_status()
|
|
146
|
+
|
|
147
|
+
# Generate compliance report
|
|
148
|
+
report = client.generate_compliance_report(
|
|
149
|
+
framework="soc2",
|
|
150
|
+
format="pdf",
|
|
151
|
+
include_evidence=True
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Get compliance score
|
|
155
|
+
score = client.get_compliance_score()
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Drift Detection
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
# Get drift metrics
|
|
162
|
+
metrics = client.get_drift_metrics()
|
|
163
|
+
|
|
164
|
+
# Get drift alerts
|
|
165
|
+
alerts = client.get_drift_alerts(severity="critical", unresolved=True)
|
|
166
|
+
|
|
167
|
+
# Acknowledge/resolve alerts
|
|
168
|
+
client.acknowledge_alert(alert_id)
|
|
169
|
+
client.resolve_alert(alert_id, notes="Fixed in v2.1")
|
|
170
|
+
|
|
171
|
+
# Get drift score
|
|
172
|
+
score = client.get_drift_score()
|
|
173
|
+
|
|
174
|
+
# Get predictions
|
|
175
|
+
predictions = client.get_drift_predictions()
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Distributed Tracing
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
# Start a trace
|
|
182
|
+
trace = client.start_trace(
|
|
183
|
+
app_id="my-app",
|
|
184
|
+
name="chat-completion",
|
|
185
|
+
user_id="user-123",
|
|
186
|
+
metadata={"session": "abc"}
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Add spans
|
|
190
|
+
span = client.start_span(
|
|
191
|
+
trace_id=trace["trace_id"],
|
|
192
|
+
name="llm-call",
|
|
193
|
+
span_type="llm",
|
|
194
|
+
model="gpt-4o"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
# End span with results
|
|
198
|
+
client.end_span(
|
|
199
|
+
span_id=span["span_id"],
|
|
200
|
+
output={"text": "Response"},
|
|
201
|
+
tokens_in=100,
|
|
202
|
+
tokens_out=50
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# End trace
|
|
206
|
+
client.end_trace(trace["trace_id"])
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Prompt Management
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
# Create prompt
|
|
213
|
+
prompt = client.create_prompt(
|
|
214
|
+
name="customer-support",
|
|
215
|
+
content="You are a helpful assistant...",
|
|
216
|
+
variables=["customer_name", "issue"],
|
|
217
|
+
tags=["support", "production"]
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Create version
|
|
221
|
+
version = client.create_prompt_version(
|
|
222
|
+
prompt_id=prompt["prompt_id"],
|
|
223
|
+
content="Updated prompt content...",
|
|
224
|
+
commit_message="Improved tone"
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Deploy to environment
|
|
228
|
+
client.deploy_prompt_version(
|
|
229
|
+
version_id=version["version_id"],
|
|
230
|
+
environment="prod"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Get deployed prompt
|
|
234
|
+
deployed = client.get_deployed_prompt(prompt["prompt_id"], "prod")
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Evaluations
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
# Create dataset
|
|
241
|
+
dataset = client.create_dataset(
|
|
242
|
+
name="qa-test-set",
|
|
243
|
+
schema_type="qa"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# Add items
|
|
247
|
+
client.add_dataset_items(dataset["dataset_id"], [
|
|
248
|
+
{"input": {"question": "What is 2+2?"}, "expected_output": {"answer": "4"}},
|
|
249
|
+
{"input": {"question": "Capital of Japan?"}, "expected_output": {"answer": "Tokyo"}}
|
|
250
|
+
])
|
|
251
|
+
|
|
252
|
+
# Run evaluation
|
|
253
|
+
run = client.create_eval_run(
|
|
254
|
+
dataset_id=dataset["dataset_id"],
|
|
255
|
+
model="gpt-4o",
|
|
256
|
+
evaluators=[
|
|
257
|
+
{"name": "correctness", "type": "llm_judge"},
|
|
258
|
+
{"name": "exact_match", "type": "exact_match"}
|
|
259
|
+
]
|
|
260
|
+
)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Semantic Caching
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
# Check cache
|
|
267
|
+
result = client.cache_lookup(input="What is the weather?", model="gpt-4o")
|
|
268
|
+
|
|
269
|
+
if result["hit"]:
|
|
270
|
+
return result["output"]
|
|
271
|
+
else:
|
|
272
|
+
# Call LLM and store
|
|
273
|
+
response = call_llm(...)
|
|
274
|
+
client.cache_store(
|
|
275
|
+
input="What is the weather?",
|
|
276
|
+
output=response,
|
|
277
|
+
model="gpt-4o"
|
|
278
|
+
)
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Agent Simulations
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
# Create simulation
|
|
285
|
+
sim = client.create_simulation(
|
|
286
|
+
name="booking-flow",
|
|
287
|
+
scenario="User wants to book a flight to Paris",
|
|
288
|
+
persona={"name": "Traveler", "traits": ["impatient", "budget-conscious"]},
|
|
289
|
+
success_criteria=[
|
|
290
|
+
{"name": "booking_complete", "description": "Flight successfully booked"}
|
|
291
|
+
],
|
|
292
|
+
max_turns=20
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# Run simulation
|
|
296
|
+
run = client.run_simulation(sim["simulation_id"])
|
|
297
|
+
|
|
298
|
+
# Get results
|
|
299
|
+
results = client.get_simulation_run(run["run_id"])
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Integrations
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
# Create Slack integration
|
|
306
|
+
client.create_integration(
|
|
307
|
+
type="slack",
|
|
308
|
+
webhook_url="https://hooks.slack.com/...",
|
|
309
|
+
channel_name="#alerts",
|
|
310
|
+
events=["high_risk", "incident", "drift_alert"]
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
# Test integration
|
|
314
|
+
client.test_integration(webhook_url, "slack")
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Model Analytics
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
# Get summary
|
|
321
|
+
summary = client.get_model_analytics_summary()
|
|
322
|
+
|
|
323
|
+
# Get historical logs
|
|
324
|
+
logs = client.get_historical_logs(
|
|
325
|
+
model="gpt-4o",
|
|
326
|
+
min_risk_score=0.7,
|
|
327
|
+
limit=100
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
# Get model benchmarks
|
|
331
|
+
benchmarks = client.get_model_benchmarks(model="gpt-4o")
|
|
332
|
+
|
|
333
|
+
# Record model switch
|
|
334
|
+
client.record_model_switch(
|
|
335
|
+
app_id="my-app",
|
|
336
|
+
new_model="gpt-4o",
|
|
337
|
+
new_provider="openai",
|
|
338
|
+
previous_model="gpt-4",
|
|
339
|
+
switch_reason="Cost optimization"
|
|
340
|
+
)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Executive Dashboard
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
# Get executive metrics
|
|
347
|
+
metrics = client.get_executive_metrics(period="7d")
|
|
348
|
+
|
|
349
|
+
# Get/update KPI targets
|
|
350
|
+
targets = client.get_kpi_targets()
|
|
351
|
+
client.update_kpi_targets({
|
|
352
|
+
"max_high_risk_percent": 5.0,
|
|
353
|
+
"target_latency_ms": 500
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
# Export metrics
|
|
357
|
+
export = client.export_executive_metrics(period="30d", format="pdf")
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Guardrails
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
# List guardrails
|
|
364
|
+
guardrails = client.get_guardrails()
|
|
365
|
+
|
|
366
|
+
# Create guardrail
|
|
367
|
+
client.create_guardrail(
|
|
368
|
+
name="block-competitors",
|
|
369
|
+
rule_type="blocked_terms",
|
|
370
|
+
action="block",
|
|
371
|
+
config={"terms": ["competitor1", "competitor2"]}
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# Get stats
|
|
375
|
+
stats = client.get_guardrail_stats()
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Custom Detections
|
|
379
|
+
|
|
380
|
+
```python
|
|
381
|
+
# Create custom detection
|
|
382
|
+
client.create_custom_detection(
|
|
383
|
+
name="financial-advice",
|
|
384
|
+
detection_type="semantic",
|
|
385
|
+
config={"description": "Detects unauthorized financial advice"},
|
|
386
|
+
severity="high"
|
|
387
|
+
)
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Benchmarks
|
|
391
|
+
|
|
392
|
+
```python
|
|
393
|
+
# Get industry benchmark report
|
|
394
|
+
report = client.get_benchmark_report(industry="fintech")
|
|
395
|
+
|
|
396
|
+
# Set your industry
|
|
397
|
+
client.set_tenant_industry("fintech")
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Exports
|
|
401
|
+
|
|
402
|
+
```python
|
|
403
|
+
# Create export
|
|
404
|
+
export = client.create_export(
|
|
405
|
+
export_type="events",
|
|
406
|
+
format="csv",
|
|
407
|
+
date_from="2024-01-01",
|
|
408
|
+
date_to="2024-01-31"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
# Check status
|
|
412
|
+
status = client.get_export_status(export["export_id"])
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Configuration
|
|
416
|
+
|
|
417
|
+
| Parameter | Default | Description |
|
|
418
|
+
|-----------|---------|-------------|
|
|
419
|
+
| `api_key` | Required | Your DriftRail API key |
|
|
420
|
+
| `app_id` | Required | Your application identifier |
|
|
421
|
+
| `base_url` | `https://api.driftrail.com` | API base URL |
|
|
422
|
+
| `timeout` | `30` | Request timeout in seconds |
|
|
423
|
+
| `fail_open` | `True` | Don't raise on errors |
|
|
424
|
+
| `guard_mode` | `fail_open` | Guard behavior on block |
|
|
425
|
+
|
|
426
|
+
## Error Handling
|
|
427
|
+
|
|
428
|
+
```python
|
|
429
|
+
from driftrail import GuardBlockedError
|
|
430
|
+
|
|
431
|
+
client = DriftRail(
|
|
432
|
+
api_key="...",
|
|
433
|
+
app_id="my-app",
|
|
434
|
+
guard_mode="fail_closed" # Raise on blocked content
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
try:
|
|
438
|
+
result = client.guard(output=response)
|
|
439
|
+
except GuardBlockedError as e:
|
|
440
|
+
print(f"Blocked: {e.result.triggered}")
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## Type Hints
|
|
444
|
+
|
|
445
|
+
Full type hints are available for all methods and responses:
|
|
446
|
+
|
|
447
|
+
```python
|
|
448
|
+
from driftrail import (
|
|
449
|
+
DriftRail,
|
|
450
|
+
IngestResponse,
|
|
451
|
+
GuardResult,
|
|
452
|
+
Incident,
|
|
453
|
+
DriftAlert,
|
|
454
|
+
Trace,
|
|
455
|
+
Span,
|
|
456
|
+
# ... and many more
|
|
457
|
+
)
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Links
|
|
461
|
+
|
|
462
|
+
- [Documentation](https://driftrail.com/docs)
|
|
463
|
+
- [API Reference](https://driftrail.com/api-reference)
|
|
464
|
+
- [Dashboard](https://app.driftrail.com)
|
|
465
|
+
- [GitHub](https://github.com/driftrail/driftrail-python)
|
|
466
|
+
|
|
467
|
+
## License
|
|
468
|
+
|
|
469
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
driftrail/__init__.py,sha256=PFuLmC8fYyXJC2IMz5272nrt7HcH57HTHADgYv2Vtbo,4083
|
|
2
|
+
driftrail/client.py,sha256=AuNb4XfJoQdouNhc7uhbbkvC6KtfQhAlGlSxZ--ZB1g,41208
|
|
3
|
+
driftrail/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
driftrail/types.py,sha256=Sk8ph9FNXk2n1cS88uL7vjrA_KwCCacFkl_tzDLWFEU,18232
|
|
5
|
+
driftrail-2.1.0.dist-info/licenses/LICENSE,sha256=c9ZcDM-aSAaN2gLxDBnXkKHd9qeTS25eXQg4i2vYQcU,1066
|
|
6
|
+
driftrail-2.1.0.dist-info/METADATA,sha256=SKppZZDT00dbxYck5mkaUT5bCAWaPvGO-psK6wKXLeg,10720
|
|
7
|
+
driftrail-2.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
+
driftrail-2.1.0.dist-info/top_level.txt,sha256=Ok_mUwZ0Sktm13smRuubG2jZTSyoQEwjsbrEHoqTTnU,10
|
|
9
|
+
driftrail-2.1.0.dist-info/RECORD,,
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: driftrail
|
|
3
|
-
Version: 2.0.0
|
|
4
|
-
Summary: DriftRail SDK - AI Safety & Observability Platform for LLM monitoring, guardrails, and compliance
|
|
5
|
-
Author-email: DriftRail <support@driftrail.com>
|
|
6
|
-
Maintainer-email: DriftRail <support@driftrail.com>
|
|
7
|
-
License: MIT
|
|
8
|
-
Project-URL: Homepage, https://driftrail.com
|
|
9
|
-
Project-URL: Documentation, https://docs.driftrail.com
|
|
10
|
-
Project-URL: Repository, https://github.com/cutmob/DriftRail-Python
|
|
11
|
-
Project-URL: Changelog, https://github.com/cutmob/DriftRail-Python/blob/main/CHANGELOG.md
|
|
12
|
-
Project-URL: Bug Tracker, https://github.com/cutmob/DriftRail-Python/issues
|
|
13
|
-
Keywords: ai,llm,observability,safety,monitoring,audit,guardrails,compliance,openai,anthropic,gemini,machine-learning,mlops
|
|
14
|
-
Classifier: Development Status :: 4 - Beta
|
|
15
|
-
Classifier: Intended Audience :: Developers
|
|
16
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
-
Classifier: Operating System :: OS Independent
|
|
18
|
-
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
-
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
27
|
-
Classifier: Topic :: System :: Monitoring
|
|
28
|
-
Classifier: Typing :: Typed
|
|
29
|
-
Requires-Python: >=3.8
|
|
30
|
-
Description-Content-Type: text/markdown
|
|
31
|
-
License-File: LICENSE
|
|
32
|
-
Provides-Extra: async
|
|
33
|
-
Requires-Dist: aiohttp>=3.8.0; extra == "async"
|
|
34
|
-
Provides-Extra: dev
|
|
35
|
-
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
36
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
37
|
-
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
38
|
-
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
39
|
-
Dynamic: license-file
|
|
40
|
-
|
|
41
|
-
# DriftRail Python SDK
|
|
42
|
-
|
|
43
|
-
[](https://pypi.org/project/driftrail/)
|
|
44
|
-
[](https://www.python.org/downloads/)
|
|
45
|
-
[](https://opensource.org/licenses/MIT)
|
|
46
|
-
|
|
47
|
-
AI Safety & Observability Platform — Monitor, classify, and audit every LLM interaction.
|
|
48
|
-
|
|
49
|
-
## Installation
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
pip install driftrail
|
|
53
|
-
|
|
54
|
-
# For async support
|
|
55
|
-
pip install driftrail[async]
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Quick Start
|
|
59
|
-
|
|
60
|
-
```python
|
|
61
|
-
from driftrail import DriftRail
|
|
62
|
-
|
|
63
|
-
client = DriftRail(
|
|
64
|
-
api_key="dr_live_...",
|
|
65
|
-
app_id="my-app"
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
# Log an LLM interaction
|
|
69
|
-
response = client.ingest(
|
|
70
|
-
model="claude-sonnet-4",
|
|
71
|
-
provider="anthropic",
|
|
72
|
-
input={"prompt": "What is the capital of France?"},
|
|
73
|
-
output={"text": "The capital of France is Paris."}
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
print(f"Event ID: {response.event_id}")
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Inline Guardrails
|
|
80
|
-
|
|
81
|
-
Block dangerous outputs BEFORE they reach users:
|
|
82
|
-
|
|
83
|
-
```python
|
|
84
|
-
from driftrail import DriftRail
|
|
85
|
-
|
|
86
|
-
client = DriftRail(api_key="...", app_id="my-app")
|
|
87
|
-
|
|
88
|
-
# Get response from your LLM
|
|
89
|
-
llm_response = your_llm_call(user_prompt)
|
|
90
|
-
|
|
91
|
-
# Guard it before returning to user
|
|
92
|
-
result = client.guard(
|
|
93
|
-
output=llm_response,
|
|
94
|
-
input=user_prompt,
|
|
95
|
-
mode="strict" # or "permissive"
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
if result.allowed:
|
|
99
|
-
return result.output # May be redacted if PII was found
|
|
100
|
-
else:
|
|
101
|
-
print(f"Blocked: {[t.reason for t in result.triggered]}")
|
|
102
|
-
return "Sorry, I can't help with that."
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Guard Modes
|
|
106
|
-
|
|
107
|
-
- `strict` (default): Blocks on medium+ risk (PII, moderate toxicity, prompt injection)
|
|
108
|
-
- `permissive`: Only blocks on high risk (severe toxicity, high-risk injection)
|
|
109
|
-
|
|
110
|
-
### Fail-Open vs Fail-Closed
|
|
111
|
-
|
|
112
|
-
```python
|
|
113
|
-
# Fail-open (default): If DriftRail is unavailable, content is allowed through
|
|
114
|
-
client = DriftRail(api_key="...", app_id="...", guard_mode="fail_open")
|
|
115
|
-
|
|
116
|
-
# Fail-closed: If DriftRail is unavailable, raises exception
|
|
117
|
-
client = DriftRail(api_key="...", app_id="...", guard_mode="fail_closed")
|
|
118
|
-
|
|
119
|
-
try:
|
|
120
|
-
result = client.guard(output=llm_response)
|
|
121
|
-
except GuardBlockedError as e:
|
|
122
|
-
print(f"Blocked: {e.result.triggered}")
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## Async Usage
|
|
126
|
-
|
|
127
|
-
```python
|
|
128
|
-
import asyncio
|
|
129
|
-
from driftrail import DriftRailAsync
|
|
130
|
-
|
|
131
|
-
async def main():
|
|
132
|
-
async with DriftRailAsync(api_key="...", app_id="my-app") as client:
|
|
133
|
-
response = await client.ingest(
|
|
134
|
-
model="claude-3",
|
|
135
|
-
provider="anthropic",
|
|
136
|
-
input={"prompt": "Hello"},
|
|
137
|
-
output={"text": "Hi there!"}
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
asyncio.run(main())
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Fire-and-Forget (Non-blocking)
|
|
144
|
-
|
|
145
|
-
```python
|
|
146
|
-
# Won't block your main thread
|
|
147
|
-
client.ingest_async(
|
|
148
|
-
model="gpt-4o",
|
|
149
|
-
provider="openai",
|
|
150
|
-
input={"prompt": "..."},
|
|
151
|
-
output={"text": "..."}
|
|
152
|
-
)
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
> ⚠️ **Serverless Warning**: Do not use `ingest_async()` in AWS Lambda, Google Cloud Functions, or other serverless environments. Use the synchronous `ingest()` method instead.
|
|
156
|
-
|
|
157
|
-
## With Metadata
|
|
158
|
-
|
|
159
|
-
```python
|
|
160
|
-
import time
|
|
161
|
-
|
|
162
|
-
start = time.time()
|
|
163
|
-
# ... your LLM call ...
|
|
164
|
-
latency = int((time.time() - start) * 1000)
|
|
165
|
-
|
|
166
|
-
client.ingest(
|
|
167
|
-
model="gpt-4o",
|
|
168
|
-
provider="openai",
|
|
169
|
-
input={"prompt": "..."},
|
|
170
|
-
output={"text": "..."},
|
|
171
|
-
metadata={
|
|
172
|
-
"latency_ms": latency,
|
|
173
|
-
"tokens_in": 50,
|
|
174
|
-
"tokens_out": 150,
|
|
175
|
-
"temperature": 0.7
|
|
176
|
-
}
|
|
177
|
-
)
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## With RAG Sources
|
|
181
|
-
|
|
182
|
-
```python
|
|
183
|
-
client.ingest(
|
|
184
|
-
model="claude-3.5-haiku",
|
|
185
|
-
provider="anthropic",
|
|
186
|
-
input={
|
|
187
|
-
"prompt": "What does our refund policy say?",
|
|
188
|
-
"retrieved_sources": [
|
|
189
|
-
{"id": "doc-123", "content": "Refunds are available within 30 days..."},
|
|
190
|
-
{"id": "doc-456", "content": "Contact support for refund requests..."}
|
|
191
|
-
]
|
|
192
|
-
},
|
|
193
|
-
output={"text": "According to our policy, refunds are available within 30 days..."}
|
|
194
|
-
)
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## Enterprise Features
|
|
198
|
-
|
|
199
|
-
```python
|
|
200
|
-
from driftrail import DriftRailEnterprise
|
|
201
|
-
|
|
202
|
-
client = DriftRailEnterprise(api_key="...", app_id="my-app")
|
|
203
|
-
|
|
204
|
-
# Incident management
|
|
205
|
-
stats = client.get_incident_stats()
|
|
206
|
-
|
|
207
|
-
# Compliance status
|
|
208
|
-
compliance = client.get_compliance_status()
|
|
209
|
-
|
|
210
|
-
# Model leaderboard
|
|
211
|
-
leaderboard = client.get_model_leaderboard(metric="avg_risk_score")
|
|
212
|
-
|
|
213
|
-
# Brand safety checks
|
|
214
|
-
violations = client.check_brand_safety("Some AI output text")
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
## Documentation
|
|
218
|
-
|
|
219
|
-
- [Full Documentation](https://docs.driftrail.com)
|
|
220
|
-
- [API Reference](https://docs.driftrail.com/api)
|
|
221
|
-
- [Dashboard](https://app.driftrail.com)
|
|
222
|
-
- [GitHub Repository](https://github.com/cutmob/DriftRail-Python)
|
|
223
|
-
|
|
224
|
-
## License
|
|
225
|
-
|
|
226
|
-
MIT
|
driftrail-2.0.0.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
driftrail/__init__.py,sha256=bM87N2M9Ii431s-lN2DAkMYceMauPGRSVY_Q6QB5aQ8,433
|
|
2
|
-
driftrail/client.py,sha256=g4XQChRpqTXhbIQo8lisH86_Tm09MLNvTRWZrSAzUas,16470
|
|
3
|
-
driftrail/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
driftrail/types.py,sha256=5WEpnl7e513b9ugtmFitC6blbMe2VC5oUV11ARYodj4,5232
|
|
5
|
-
driftrail-2.0.0.dist-info/licenses/LICENSE,sha256=c9ZcDM-aSAaN2gLxDBnXkKHd9qeTS25eXQg4i2vYQcU,1066
|
|
6
|
-
driftrail-2.0.0.dist-info/METADATA,sha256=y5SA5wuDhSJCDKWQgQaoPYHMvYg3IwPQL-uO3KlegWA,6334
|
|
7
|
-
driftrail-2.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
-
driftrail-2.0.0.dist-info/top_level.txt,sha256=Ok_mUwZ0Sktm13smRuubG2jZTSyoQEwjsbrEHoqTTnU,10
|
|
9
|
-
driftrail-2.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|