provy-sdk 0.5.0__tar.gz
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.
- provy_sdk-0.5.0/PKG-INFO +218 -0
- provy_sdk-0.5.0/README.md +189 -0
- provy_sdk-0.5.0/provy/__init__.py +95 -0
- provy_sdk-0.5.0/provy/client.py +462 -0
- provy_sdk-0.5.0/provy/db.py +30 -0
- provy_sdk-0.5.0/provy/engine/__init__.py +43 -0
- provy_sdk-0.5.0/provy/engine/eval_engine.py +459 -0
- provy_sdk-0.5.0/provy/engine/loader.py +60 -0
- provy_sdk-0.5.0/provy/engine/pattern_detector.py +800 -0
- provy_sdk-0.5.0/provy/engine/rca_engine.py +158 -0
- provy_sdk-0.5.0/provy/evals.py +53 -0
- provy_sdk-0.5.0/provy/judge.py +241 -0
- provy_sdk-0.5.0/provy/session.py +415 -0
- provy_sdk-0.5.0/provy/transport.py +220 -0
- provy_sdk-0.5.0/provy_sdk.egg-info/PKG-INFO +218 -0
- provy_sdk-0.5.0/provy_sdk.egg-info/SOURCES.txt +22 -0
- provy_sdk-0.5.0/provy_sdk.egg-info/dependency_links.txt +1 -0
- provy_sdk-0.5.0/provy_sdk.egg-info/requires.txt +19 -0
- provy_sdk-0.5.0/provy_sdk.egg-info/top_level.txt +1 -0
- provy_sdk-0.5.0/pyproject.toml +43 -0
- provy_sdk-0.5.0/setup.cfg +4 -0
- provy_sdk-0.5.0/tests/test_engine.py +608 -0
- provy_sdk-0.5.0/tests/test_session.py +100 -0
- provy_sdk-0.5.0/tests/test_transport.py +194 -0
provy_sdk-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: provy-sdk
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Python SDK for Provy: prove your AI agents actually worked
|
|
5
|
+
Author: Provy
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Documentation, https://provy.ai/knowledge/index
|
|
8
|
+
Project-URL: Issues, https://github.com/amitgarg73/provy-sdk/issues
|
|
9
|
+
Project-URL: Homepage, https://provy.ai
|
|
10
|
+
Project-URL: Repository, https://github.com/amitgarg73/provy-sdk
|
|
11
|
+
Keywords: observability,llm,agents,opentelemetry,evals,outcome-assurance
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: requests>=2.28
|
|
15
|
+
Requires-Dist: pytz>=2023.3
|
|
16
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
17
|
+
Provides-Extra: judge
|
|
18
|
+
Requires-Dist: anthropic>=0.25.0; extra == "judge"
|
|
19
|
+
Provides-Extra: engine
|
|
20
|
+
Requires-Dist: supabase>=2.0.0; extra == "engine"
|
|
21
|
+
Provides-Extra: otel
|
|
22
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == "otel"
|
|
23
|
+
Requires-Dist: opentelemetry-api>=1.20.0; extra == "otel"
|
|
24
|
+
Provides-Extra: all
|
|
25
|
+
Requires-Dist: anthropic>=0.25.0; extra == "all"
|
|
26
|
+
Requires-Dist: supabase>=2.0.0; extra == "all"
|
|
27
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == "all"
|
|
28
|
+
Requires-Dist: opentelemetry-api>=1.20.0; extra == "all"
|
|
29
|
+
|
|
30
|
+
# provy-sdk
|
|
31
|
+
|
|
32
|
+
Python SDK for [Provy](https://provy.ai): prove your AI agents actually worked.
|
|
33
|
+
|
|
34
|
+
Send every session, agent step and evaluation with an ingest key. No database credentials and no
|
|
35
|
+
Provy-side configuration — close a session and it appears on your dashboard.
|
|
36
|
+
|
|
37
|
+
> **A note on names.** You may see `argus` inside: environment variables such as `ARGUS_INGEST_KEY`
|
|
38
|
+
> and `ARGUS_URL` still work, and OpenTelemetry attributes are still `argus.*`. Argus is the original
|
|
39
|
+
> codename, and those names are kept for wire compatibility so existing integrations keep working.
|
|
40
|
+
> Everything you actually type is `provy`.
|
|
41
|
+
|
|
42
|
+
## Reliability
|
|
43
|
+
|
|
44
|
+
Telemetry that silently disappears is worse than none, so this client is built not to lose spans:
|
|
45
|
+
|
|
46
|
+
- **Retries** transient failures with backoff, honouring `Retry-After`. A timeout or a 503 delays
|
|
47
|
+
your data rather than destroying it.
|
|
48
|
+
- **Buffers and batches** spans, flushing on a background thread and again at process exit, so a
|
|
49
|
+
short script cannot end with telemetry still in memory.
|
|
50
|
+
- **Never silent.** Anything dropped is counted and logged, and the counts are readable at
|
|
51
|
+
`client.buffer_stats`.
|
|
52
|
+
- **Never raises into your agent.** A failed send is our problem, not a crash in your pipeline.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install provy-sdk
|
|
60
|
+
```
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The base install is the ingest client only (just `requests`). Optional extras:
|
|
64
|
+
|
|
65
|
+
| Extra | Adds | For |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `provy-sdk[otel]` | OpenTelemetry SDK | streaming existing OTel spans via `ProvyExporter` |
|
|
68
|
+
| `provy-sdk[judge]` | `anthropic` | running the LLM-as-judge in your own pipeline (circuit breakers) |
|
|
69
|
+
| `provy-sdk[engine]` | `supabase` | the legacy direct-to-database path (prefer the ingest API instead) |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Connect
|
|
74
|
+
|
|
75
|
+
Get an ingest key from Provy: **Agent Fleets → your fleet → Reveal key**. Set it in your environment:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
export PROVY_API_KEY=argus_... # key values are still prefixed argus_
|
|
79
|
+
# optional, defaults to the hosted app:
|
|
80
|
+
export PROVY_URL=https://provy.ai
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
That key authenticates your fleet. It is the only credential you need.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Quickstart — direct ingest
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from provy import ProvyClient
|
|
91
|
+
|
|
92
|
+
provy = ProvyClient() # reads PROVY_API_KEY from the environment
|
|
93
|
+
|
|
94
|
+
session_id = provy.open_session("premarket")
|
|
95
|
+
|
|
96
|
+
provy.trace(
|
|
97
|
+
session_id = session_id,
|
|
98
|
+
agent = "research",
|
|
99
|
+
step_type = "agent_step", # llm_call | tool_call | agent_step | decision | error
|
|
100
|
+
outcome = "Generated AAPL thesis",
|
|
101
|
+
latency_ms = 1240,
|
|
102
|
+
tokens_in = 800,
|
|
103
|
+
tokens_out = 150,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
provy.close_session(session_id, result_summary="Trade plan ready")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Open **Sessions** in Provy — your run appears within seconds.
|
|
110
|
+
|
|
111
|
+
The decorator form auto-traces a function:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
@provy.trace_fn(agent="research", step_type="agent_step")
|
|
115
|
+
def run_research(ticker):
|
|
116
|
+
...
|
|
117
|
+
|
|
118
|
+
run_research("AAPL", session_id=session_id)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Already on OpenTelemetry?
|
|
124
|
+
|
|
125
|
+
If your pipeline emits OTel spans (LangChain, CrewAI, AutoGen, LlamaIndex, or raw OTel), attach the exporter and stream them — no per-step calls:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pip install "provy-sdk[otel]"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
133
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
134
|
+
from provy import ProvyExporter
|
|
135
|
+
|
|
136
|
+
provider = TracerProvider()
|
|
137
|
+
provider.add_span_processor(BatchSpanProcessor(ProvyExporter(api_key="provy_...")))
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Provy auto-detects the convention (OpenInference, OpenLLMetry/Traceloop, Langfuse, OTel GenAI) and builds the session from your spans.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Quality scoring
|
|
145
|
+
|
|
146
|
+
By default Provy runs the LLM-as-judge **server-side** on the traces you send — no SDK code, no key of yours. Configure criteria in **Eval Manager** and scores appear on the Quality page.
|
|
147
|
+
|
|
148
|
+
Run the judge **in your own pipeline** only when you want the verdict before an output is used (circuit breakers):
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pip install "provy-sdk[judge]" # adds anthropic
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from provy import evaluate_session_outputs
|
|
156
|
+
|
|
157
|
+
evaluate_session_outputs(session_id, {"research": research_output_text})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Needs `ANTHROPIC_API_KEY` in your environment. Same judge core as the server side.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Business outcomes
|
|
165
|
+
|
|
166
|
+
For metrics you compute yourself (no LLM), write them with `write_eval()` — they land in **Outcomes**:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from provy import write_eval
|
|
170
|
+
|
|
171
|
+
write_eval(
|
|
172
|
+
session_id = session_id,
|
|
173
|
+
eval_name = "approval_rate",
|
|
174
|
+
agent = "risk",
|
|
175
|
+
score = 0.6,
|
|
176
|
+
passed = True,
|
|
177
|
+
threshold = 0.2,
|
|
178
|
+
reasoning = "3 of 5 proposals approved",
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## API reference
|
|
185
|
+
|
|
186
|
+
### `ProvyClient(ingest_key=None, base_url=None)`
|
|
187
|
+
Reads `PROVY_API_KEY` / `PROVY_URL` from the environment when arguments are omitted (legacy `ARGUS_INGEST_KEY` / `ARGUS_URL` still work).
|
|
188
|
+
|
|
189
|
+
| Method | When to call |
|
|
190
|
+
|---|---|
|
|
191
|
+
| `open_session(session_type, external_id=None, metadata=None)` | start of a run; returns `session_id` |
|
|
192
|
+
| `trace(session_id, agent, step_type, outcome, ...)` | each step; returns the span id |
|
|
193
|
+
| `close_session(session_id, status="completed", result_summary=None, terminal_reason=None)` | end of the run |
|
|
194
|
+
| `trace_fn(agent, step_type="agent_step")` | decorator that auto-traces a function |
|
|
195
|
+
|
|
196
|
+
### `ProvyExporter(api_key, endpoint=None)`
|
|
197
|
+
OTel `SpanExporter`. Attach to any `TracerProvider`. Needs the `otel` extra.
|
|
198
|
+
|
|
199
|
+
### `evaluate_session_outputs(session_id, agent_outputs)`
|
|
200
|
+
Client-side LLM-as-judge. Needs the `judge` extra and `ANTHROPIC_API_KEY`.
|
|
201
|
+
|
|
202
|
+
### `write_eval(session_id, eval_name, agent, score, passed, threshold, reasoning, layer=5)`
|
|
203
|
+
Writes one business-outcome eval row.
|
|
204
|
+
|
|
205
|
+
> **Legacy:** `TraceLogger` (direct database writes via the `engine` extra) predates the ingest API. New pipelines should use `ProvyClient`. `TraceLogger` remains for existing internal pipelines.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Examples
|
|
210
|
+
|
|
211
|
+
- `examples/otel_quickstart.py` — stream OTel spans to Provy
|
|
212
|
+
- `examples/github-actions-otel.yml` — run a pipeline in GitHub Actions and stream to Provy
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Support
|
|
217
|
+
|
|
218
|
+
Open an issue at [github.com/amitgarg73/provy-sdk](https://github.com/amitgarg73/provy-sdk/issues).
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# provy-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK for [Provy](https://provy.ai): prove your AI agents actually worked.
|
|
4
|
+
|
|
5
|
+
Send every session, agent step and evaluation with an ingest key. No database credentials and no
|
|
6
|
+
Provy-side configuration — close a session and it appears on your dashboard.
|
|
7
|
+
|
|
8
|
+
> **A note on names.** You may see `argus` inside: environment variables such as `ARGUS_INGEST_KEY`
|
|
9
|
+
> and `ARGUS_URL` still work, and OpenTelemetry attributes are still `argus.*`. Argus is the original
|
|
10
|
+
> codename, and those names are kept for wire compatibility so existing integrations keep working.
|
|
11
|
+
> Everything you actually type is `provy`.
|
|
12
|
+
|
|
13
|
+
## Reliability
|
|
14
|
+
|
|
15
|
+
Telemetry that silently disappears is worse than none, so this client is built not to lose spans:
|
|
16
|
+
|
|
17
|
+
- **Retries** transient failures with backoff, honouring `Retry-After`. A timeout or a 503 delays
|
|
18
|
+
your data rather than destroying it.
|
|
19
|
+
- **Buffers and batches** spans, flushing on a background thread and again at process exit, so a
|
|
20
|
+
short script cannot end with telemetry still in memory.
|
|
21
|
+
- **Never silent.** Anything dropped is counted and logged, and the counts are readable at
|
|
22
|
+
`client.buffer_stats`.
|
|
23
|
+
- **Never raises into your agent.** A failed send is our problem, not a crash in your pipeline.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install provy-sdk
|
|
31
|
+
```
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The base install is the ingest client only (just `requests`). Optional extras:
|
|
35
|
+
|
|
36
|
+
| Extra | Adds | For |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `provy-sdk[otel]` | OpenTelemetry SDK | streaming existing OTel spans via `ProvyExporter` |
|
|
39
|
+
| `provy-sdk[judge]` | `anthropic` | running the LLM-as-judge in your own pipeline (circuit breakers) |
|
|
40
|
+
| `provy-sdk[engine]` | `supabase` | the legacy direct-to-database path (prefer the ingest API instead) |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Connect
|
|
45
|
+
|
|
46
|
+
Get an ingest key from Provy: **Agent Fleets → your fleet → Reveal key**. Set it in your environment:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
export PROVY_API_KEY=argus_... # key values are still prefixed argus_
|
|
50
|
+
# optional, defaults to the hosted app:
|
|
51
|
+
export PROVY_URL=https://provy.ai
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
That key authenticates your fleet. It is the only credential you need.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Quickstart — direct ingest
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from provy import ProvyClient
|
|
62
|
+
|
|
63
|
+
provy = ProvyClient() # reads PROVY_API_KEY from the environment
|
|
64
|
+
|
|
65
|
+
session_id = provy.open_session("premarket")
|
|
66
|
+
|
|
67
|
+
provy.trace(
|
|
68
|
+
session_id = session_id,
|
|
69
|
+
agent = "research",
|
|
70
|
+
step_type = "agent_step", # llm_call | tool_call | agent_step | decision | error
|
|
71
|
+
outcome = "Generated AAPL thesis",
|
|
72
|
+
latency_ms = 1240,
|
|
73
|
+
tokens_in = 800,
|
|
74
|
+
tokens_out = 150,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
provy.close_session(session_id, result_summary="Trade plan ready")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Open **Sessions** in Provy — your run appears within seconds.
|
|
81
|
+
|
|
82
|
+
The decorator form auto-traces a function:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
@provy.trace_fn(agent="research", step_type="agent_step")
|
|
86
|
+
def run_research(ticker):
|
|
87
|
+
...
|
|
88
|
+
|
|
89
|
+
run_research("AAPL", session_id=session_id)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Already on OpenTelemetry?
|
|
95
|
+
|
|
96
|
+
If your pipeline emits OTel spans (LangChain, CrewAI, AutoGen, LlamaIndex, or raw OTel), attach the exporter and stream them — no per-step calls:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install "provy-sdk[otel]"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
104
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
105
|
+
from provy import ProvyExporter
|
|
106
|
+
|
|
107
|
+
provider = TracerProvider()
|
|
108
|
+
provider.add_span_processor(BatchSpanProcessor(ProvyExporter(api_key="provy_...")))
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Provy auto-detects the convention (OpenInference, OpenLLMetry/Traceloop, Langfuse, OTel GenAI) and builds the session from your spans.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Quality scoring
|
|
116
|
+
|
|
117
|
+
By default Provy runs the LLM-as-judge **server-side** on the traces you send — no SDK code, no key of yours. Configure criteria in **Eval Manager** and scores appear on the Quality page.
|
|
118
|
+
|
|
119
|
+
Run the judge **in your own pipeline** only when you want the verdict before an output is used (circuit breakers):
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pip install "provy-sdk[judge]" # adds anthropic
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from provy import evaluate_session_outputs
|
|
127
|
+
|
|
128
|
+
evaluate_session_outputs(session_id, {"research": research_output_text})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Needs `ANTHROPIC_API_KEY` in your environment. Same judge core as the server side.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Business outcomes
|
|
136
|
+
|
|
137
|
+
For metrics you compute yourself (no LLM), write them with `write_eval()` — they land in **Outcomes**:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from provy import write_eval
|
|
141
|
+
|
|
142
|
+
write_eval(
|
|
143
|
+
session_id = session_id,
|
|
144
|
+
eval_name = "approval_rate",
|
|
145
|
+
agent = "risk",
|
|
146
|
+
score = 0.6,
|
|
147
|
+
passed = True,
|
|
148
|
+
threshold = 0.2,
|
|
149
|
+
reasoning = "3 of 5 proposals approved",
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## API reference
|
|
156
|
+
|
|
157
|
+
### `ProvyClient(ingest_key=None, base_url=None)`
|
|
158
|
+
Reads `PROVY_API_KEY` / `PROVY_URL` from the environment when arguments are omitted (legacy `ARGUS_INGEST_KEY` / `ARGUS_URL` still work).
|
|
159
|
+
|
|
160
|
+
| Method | When to call |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `open_session(session_type, external_id=None, metadata=None)` | start of a run; returns `session_id` |
|
|
163
|
+
| `trace(session_id, agent, step_type, outcome, ...)` | each step; returns the span id |
|
|
164
|
+
| `close_session(session_id, status="completed", result_summary=None, terminal_reason=None)` | end of the run |
|
|
165
|
+
| `trace_fn(agent, step_type="agent_step")` | decorator that auto-traces a function |
|
|
166
|
+
|
|
167
|
+
### `ProvyExporter(api_key, endpoint=None)`
|
|
168
|
+
OTel `SpanExporter`. Attach to any `TracerProvider`. Needs the `otel` extra.
|
|
169
|
+
|
|
170
|
+
### `evaluate_session_outputs(session_id, agent_outputs)`
|
|
171
|
+
Client-side LLM-as-judge. Needs the `judge` extra and `ANTHROPIC_API_KEY`.
|
|
172
|
+
|
|
173
|
+
### `write_eval(session_id, eval_name, agent, score, passed, threshold, reasoning, layer=5)`
|
|
174
|
+
Writes one business-outcome eval row.
|
|
175
|
+
|
|
176
|
+
> **Legacy:** `TraceLogger` (direct database writes via the `engine` extra) predates the ingest API. New pipelines should use `ProvyClient`. `TraceLogger` remains for existing internal pipelines.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Examples
|
|
181
|
+
|
|
182
|
+
- `examples/otel_quickstart.py` — stream OTel spans to Provy
|
|
183
|
+
- `examples/github-actions-otel.yml` — run a pipeline in GitHub Actions and stream to Provy
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Support
|
|
188
|
+
|
|
189
|
+
Open an issue at [github.com/amitgarg73/provy-sdk](https://github.com/amitgarg73/provy-sdk/issues).
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provy SDK.
|
|
3
|
+
|
|
4
|
+
Importing `provy` is lightweight: it pulls in only the ingest client (REST + OTel
|
|
5
|
+
exporter), which needs `requests`. The optional pieces load on first use and tell
|
|
6
|
+
you which extra to install if it is missing:
|
|
7
|
+
|
|
8
|
+
- the LLM-as-judge → pip install "provy-sdk[judge]" (anthropic)
|
|
9
|
+
- the local eval/RCA engine → pip install "provy-sdk[engine]" (supabase; legacy
|
|
10
|
+
direct-DB path — prefer the ingest API)
|
|
11
|
+
|
|
12
|
+
So a tenant who just wants to send traces installs the base package and nothing else.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import importlib
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
# ── Eager, lightweight (ingest client — requests only) ──────────────────────────
|
|
20
|
+
from provy.client import ProvyClient, ProvyExporter
|
|
21
|
+
from provy.session import TraceLogger
|
|
22
|
+
from provy.evals import write_eval
|
|
23
|
+
|
|
24
|
+
__version__ = "0.5.0"
|
|
25
|
+
|
|
26
|
+
# ── Lazy, heavy (loaded on first access; mapped to the extra that provides them) ──
|
|
27
|
+
# name -> (module, attribute, extra)
|
|
28
|
+
_LAZY: dict[str, tuple[str, str, str]] = {
|
|
29
|
+
# LLM-as-judge (anthropic)
|
|
30
|
+
"evaluate_session_outputs": ("provy.judge", "evaluate_session_outputs", "judge"),
|
|
31
|
+
# local eval + pattern + RCA engine (supabase, legacy direct-DB)
|
|
32
|
+
"EvalResult": ("provy.engine", "EvalResult", "engine"),
|
|
33
|
+
"Incident": ("provy.engine", "Incident", "engine"),
|
|
34
|
+
"run_evals_from_config": ("provy.engine", "run_evals_from_config", "engine"),
|
|
35
|
+
"run_all_detectors": ("provy.engine", "run_all_detectors", "engine"),
|
|
36
|
+
"run_quality_detectors": ("provy.engine", "run_quality_detectors", "engine"),
|
|
37
|
+
"run_evals_and_persist": ("provy.engine", "run_evals_and_persist", "engine"),
|
|
38
|
+
"run_detectors_and_persist": ("provy.engine", "run_detectors_and_persist", "engine"),
|
|
39
|
+
"compute_shadow_cb_fires": ("provy.engine", "compute_shadow_cb_fires", "engine"),
|
|
40
|
+
"build_annotated_call_stack":("provy.engine", "build_annotated_call_stack", "engine"),
|
|
41
|
+
"generate_fix_suggestion": ("provy.engine", "generate_fix_suggestion", "engine"),
|
|
42
|
+
"summarize_incident": ("provy.engine", "summarize_incident", "engine"),
|
|
43
|
+
"load_pipeline_config": ("provy.engine", "load_pipeline_config", "engine"),
|
|
44
|
+
"load_eval_configs": ("provy.engine", "load_eval_configs", "engine"),
|
|
45
|
+
"load_pipeline_agents": ("provy.engine", "load_pipeline_agents", "engine"),
|
|
46
|
+
"register_eval": ("provy.engine", "register_eval", "engine"),
|
|
47
|
+
"get_registry": ("provy.engine", "get_registry", "engine"),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def __getattr__(name: str) -> Any: # PEP 562 — module-level lazy attributes
|
|
52
|
+
target = _LAZY.get(name)
|
|
53
|
+
if target is None:
|
|
54
|
+
raise AttributeError(f"module 'provy' has no attribute {name!r}")
|
|
55
|
+
module, attr, extra = target
|
|
56
|
+
try:
|
|
57
|
+
mod = importlib.import_module(module)
|
|
58
|
+
except ImportError as exc:
|
|
59
|
+
raise ImportError(
|
|
60
|
+
f"{name!r} needs the '{extra}' extra. Install it with: "
|
|
61
|
+
f'pip install "provy-sdk[{extra}]"'
|
|
62
|
+
) from exc
|
|
63
|
+
return getattr(mod, attr)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def __dir__() -> list[str]:
|
|
67
|
+
return sorted(__all__)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
# ingest client (base)
|
|
72
|
+
"ProvyClient",
|
|
73
|
+
"ProvyExporter",
|
|
74
|
+
"TraceLogger",
|
|
75
|
+
"write_eval",
|
|
76
|
+
# LLM-as-judge (extra: judge)
|
|
77
|
+
"evaluate_session_outputs",
|
|
78
|
+
# local engine (extra: engine)
|
|
79
|
+
"EvalResult",
|
|
80
|
+
"Incident",
|
|
81
|
+
"run_evals_from_config",
|
|
82
|
+
"run_all_detectors",
|
|
83
|
+
"run_quality_detectors",
|
|
84
|
+
"run_evals_and_persist",
|
|
85
|
+
"run_detectors_and_persist",
|
|
86
|
+
"compute_shadow_cb_fires",
|
|
87
|
+
"build_annotated_call_stack",
|
|
88
|
+
"generate_fix_suggestion",
|
|
89
|
+
"summarize_incident",
|
|
90
|
+
"load_pipeline_config",
|
|
91
|
+
"load_eval_configs",
|
|
92
|
+
"load_pipeline_agents",
|
|
93
|
+
"register_eval",
|
|
94
|
+
"get_registry",
|
|
95
|
+
]
|