agentx-python 0.8.13__tar.gz → 0.8.14__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.
- {agentx_python-0.8.13 → agentx_python-0.8.14}/PKG-INFO +22 -13
- {agentx_python-0.8.13 → agentx_python-0.8.14}/README.md +19 -11
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/anthropic.py +1 -1
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/crewai.py +1 -1
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/version.py +2 -2
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx_python.egg-info/PKG-INFO +22 -13
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx_python.egg-info/SOURCES.txt +1 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx_python.egg-info/requires.txt +1 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/setup.py +2 -1
- agentx_python-0.8.14/tests/test_selfhost_compat.py +424 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/LICENSE +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/__init__.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/agentx.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/cli.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/__init__.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/_term.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/adapters/__init__.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/adapters/http_endpoint.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/adapters/precomputed.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/adapters/raw.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/client.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/datasets.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/evaluation_settings.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/models.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/prompts.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/reporting.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/results.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/runner.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/tool_schemas.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/evaluations/tracing.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/exceptions.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/export.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/feedback.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/__init__.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/_traced_call.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/autogen.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/databricks.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/google_adk.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/google_genai.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/langchain.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/litellm.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/llamaindex.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/moveworks.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/openai.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/integrations/openai_agents.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/__init__.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/agents.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/client.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/judge_scorers.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/models.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/online_evaluators.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/patterns.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/profile.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/review_queue.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/rules.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/scorers.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/sessions.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/monitor/signals.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/outcomes.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/projects.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/py.typed +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/resources/__init__.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/resources/agent.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/resources/conversation.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/resources/workforce.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/testing.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/traces.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/tracing/__init__.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/tracing/ci_types.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/tracing/eval_scope.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/tracing/framework_detect.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/tracing/ingest_client.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/tracing/tracer.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx/util.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx_python.egg-info/dependency_links.txt +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx_python.egg-info/entry_points.txt +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx_python.egg-info/not-zip-safe +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/agentx_python.egg-info/top_level.txt +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/setup.cfg +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_cli_launcher.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_deep_dive_fixes.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_docs_match_sdk.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_eval_scope.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_framework_detect.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_integration.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_integrations.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_judge_scorers.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_pairwise.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_review_queue.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_runner_features.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_selfhost_analysis_fallback.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_span_tree.py +0 -0
- {agentx_python-0.8.13 → agentx_python-0.8.14}/tests/test_testing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentx-python
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.14
|
|
4
4
|
Summary: Official Python SDK for AgentX (https://www.agentx.so/)
|
|
5
5
|
Home-page: https://github.com/AgentX-ai/AgentX-python
|
|
6
6
|
Author: Robin Wang and AgentX Team
|
|
@@ -8,7 +8,7 @@ Author-email: contact@agentx.so
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
14
|
Requires-Dist: urllib3>=1.26.11
|
|
@@ -50,6 +50,7 @@ Requires-Dist: litellm>=1.0.0; extra == "all"
|
|
|
50
50
|
Requires-Dist: llama-index-core>=0.10.0; extra == "all"
|
|
51
51
|
Requires-Dist: autogen-agentchat>=0.4.0; extra == "all"
|
|
52
52
|
Requires-Dist: autogen-core>=0.4.0; extra == "all"
|
|
53
|
+
Requires-Dist: mlflow>=3.6.0; extra == "all"
|
|
53
54
|
Dynamic: author
|
|
54
55
|
Dynamic: author-email
|
|
55
56
|
Dynamic: classifier
|
|
@@ -109,12 +110,14 @@ pip install --upgrade agentx-python
|
|
|
109
110
|
|
|
110
111
|
Requires Python 3.9 or newer.
|
|
111
112
|
|
|
112
|
-
#### Run self
|
|
113
|
+
#### Run the self-host governance suite locally
|
|
113
114
|
|
|
114
|
-
```
|
|
115
|
-
agentx-trace-eval --dev
|
|
115
|
+
```bash
|
|
116
|
+
agentx-trace-eval --dev
|
|
116
117
|
```
|
|
117
118
|
|
|
119
|
+
(See [Self-host](#self-host) below for what this downloads and how to point the SDK at it.)
|
|
120
|
+
|
|
118
121
|
---
|
|
119
122
|
|
|
120
123
|
## Quick start
|
|
@@ -137,7 +140,7 @@ report = (
|
|
|
137
140
|
.analyze()
|
|
138
141
|
)
|
|
139
142
|
|
|
140
|
-
print(report.average_rating) # LLM-graded score, 0
|
|
143
|
+
print(report.average_rating) # LLM-graded score, 0-10
|
|
141
144
|
print(report.summary) # AI-generated narrative from .analyze()
|
|
142
145
|
```
|
|
143
146
|
|
|
@@ -158,9 +161,9 @@ report = (
|
|
|
158
161
|
.analyze()
|
|
159
162
|
)
|
|
160
163
|
|
|
161
|
-
print(report.average_rating) # LLM-graded score, 0
|
|
162
|
-
print(report.cosine_similarity) # embedding cosine, 0
|
|
163
|
-
print(report.jaccard_similarity) # token-set overlap, 0
|
|
164
|
+
print(report.average_rating) # LLM-graded score, 0-10
|
|
165
|
+
print(report.cosine_similarity) # embedding cosine, 0-1 (None if not enabled)
|
|
166
|
+
print(report.jaccard_similarity) # token-set overlap, 0-1 (None if not enabled)
|
|
164
167
|
|
|
165
168
|
print(report.summary) # AI-generated narrative from .analyze()
|
|
166
169
|
print(report.recommendations) # list of prioritized, actionable fixes
|
|
@@ -184,7 +187,7 @@ client.evaluations.run(
|
|
|
184
187
|
|
|
185
188
|
See [Prompt registry](EVALUATIONS.md#prompt-registry) in the full guide, or [self-host's docs](https://docs.agentx.so/improve/prompt-management) for the "Suggest improvement" dashboard flow (self-host only - no hosted-SaaS equivalent yet).
|
|
186
189
|
|
|
187
|
-
On self-host, a finalized run can also **gate a CI job**: `run.gate(fail_under=7, no_regression=True)` (on the run context `.execute()` returns) checks the run's average rating against an absolute floor and/or the dataset's previous run, prints per-check verdicts into the CI log, and returns
|
|
190
|
+
On self-host, a finalized run can also **gate a CI job**: `run.gate(fail_under=7, no_regression=True)` (on the run context `.execute()` returns) checks the run's average rating against an absolute floor and/or the dataset's previous run, prints per-check verdicts into the CI log, and returns a `GateResult` - `sys.exit(gate.exit_code)` blocks the merge on regression. Recorded gates appear in the dashboard's CI Gates tab. See [self-host's CI docs](https://docs.agentx.so/integrations/self-host-ci) for the GitHub Actions recipe.
|
|
188
191
|
|
|
189
192
|
See **[EVALUATIONS.md](EVALUATIONS.md)** for the full guide - dataset builder, framework adapters, similarity metrics, smoke testing, judge configuration, prompt registry, and the complete API reference.
|
|
190
193
|
|
|
@@ -252,6 +255,10 @@ extra:
|
|
|
252
255
|
| LlamaIndex | `pip install "agentx-python[llamaindex]"` | `AgentXLlamaIndexHandler` |
|
|
253
256
|
| AutoGen | `pip install "agentx-python[autogen]"` | `AgentXAutoGenObserver` |
|
|
254
257
|
|
|
258
|
+
Two more platforms are covered by **pull importers** rather than in-process hooks, each with its
|
|
259
|
+
own CLI: `agentx-moveworks` (Moveworks Data API sync, no extra needed) and `agentx-databricks`
|
|
260
|
+
(`pip install "agentx-python[databricks]"`, MLflow/Databricks trace sync).
|
|
261
|
+
|
|
255
262
|
Or plain Python - wrap any function with `@tracer.trace(...)` and it just works, no framework
|
|
256
263
|
required. Tracing is **platform agnostic**: each integration stamps its platform label
|
|
257
264
|
automatically, a plain trace auto-detects the one orchestration framework imported in the
|
|
@@ -292,12 +299,14 @@ for signal in client.monitor.signals.list(severity="high"):
|
|
|
292
299
|
print(signal.summary, signal.occurrence_count)
|
|
293
300
|
```
|
|
294
301
|
|
|
295
|
-
Per-agent
|
|
302
|
+
Per-agent monitoring settings (enable/disable, detection categories, notification channels) are `client.monitor.profile.get()`/`.update()`:
|
|
296
303
|
|
|
297
304
|
```python
|
|
298
|
-
client.monitor.profile.update("agent_123",
|
|
305
|
+
client.monitor.profile.update("agent_123", info_detection_enabled=False)
|
|
299
306
|
```
|
|
300
307
|
|
|
308
|
+
On self-host, coverage mode, sample rate, retention, and the built-in latency threshold are project-level defaults set in the dashboard's Platform Settings; `update()` still accepts them for wire compatibility, but only the per-agent fields above take effect there.
|
|
309
|
+
|
|
301
310
|
Self-host also has **online evaluators**: a real LLM judge scoring a sample of live traffic continuously, distinct from a pattern's rule-matching. A score below `alert_threshold` raises a signal the same way a failing pattern does, deduped and triage-ready in `client.monitor.signals`.
|
|
302
311
|
|
|
303
312
|
```python
|
|
@@ -371,7 +380,7 @@ export AGENTX_API_BASE_URL=http://localhost:4700/api/v1
|
|
|
371
380
|
export AGENTX_API_KEY=<printed by agentx-trace-eval on first run>
|
|
372
381
|
```
|
|
373
382
|
|
|
374
|
-
`agentx-trace-eval` isn't this SDK's own code - the engine itself is a separate, compiled binary, downloaded on demand rather than bundled into this package, so installing `agentx-python` doesn't get any heavier for the (much more common) case of just talking to the hosted AgentX API. See that repo's README for what's included, and `AGENTX_INSTALL_DIR`/`AGENTX_TRACE_EVAL_VERSION`/`AGENTX_TRACE_EVAL_SKIP_WEB` env vars to control where/what it installs.
|
|
383
|
+
`agentx-trace-eval` isn't this SDK's own code - the engine itself is a separate, compiled binary, downloaded on demand rather than bundled into this package, so installing `agentx-python` doesn't get any heavier for the (much more common) case of just talking to the hosted AgentX API. Each SDK release pins the engine release it was tested against and converges the install to that pin, so upgrading the SDK upgrades the engine too. Two flags to know: `--update` (consumed by this launcher) force-reinstalls the resolved engine release, while `--upgrade` passes through to `agentx-server` and re-downloads the dashboard bundle before serving. See that repo's README for what's included, and the `AGENTX_INSTALL_DIR`/`AGENTX_TRACE_EVAL_VERSION`/`AGENTX_TRACE_EVAL_SKIP_WEB` env vars to control where/what it installs.
|
|
375
384
|
|
|
376
385
|
---
|
|
377
386
|
|
|
@@ -45,12 +45,14 @@ pip install --upgrade agentx-python
|
|
|
45
45
|
|
|
46
46
|
Requires Python 3.9 or newer.
|
|
47
47
|
|
|
48
|
-
#### Run self
|
|
48
|
+
#### Run the self-host governance suite locally
|
|
49
49
|
|
|
50
|
-
```
|
|
51
|
-
agentx-trace-eval --dev
|
|
50
|
+
```bash
|
|
51
|
+
agentx-trace-eval --dev
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
(See [Self-host](#self-host) below for what this downloads and how to point the SDK at it.)
|
|
55
|
+
|
|
54
56
|
---
|
|
55
57
|
|
|
56
58
|
## Quick start
|
|
@@ -73,7 +75,7 @@ report = (
|
|
|
73
75
|
.analyze()
|
|
74
76
|
)
|
|
75
77
|
|
|
76
|
-
print(report.average_rating) # LLM-graded score, 0
|
|
78
|
+
print(report.average_rating) # LLM-graded score, 0-10
|
|
77
79
|
print(report.summary) # AI-generated narrative from .analyze()
|
|
78
80
|
```
|
|
79
81
|
|
|
@@ -94,9 +96,9 @@ report = (
|
|
|
94
96
|
.analyze()
|
|
95
97
|
)
|
|
96
98
|
|
|
97
|
-
print(report.average_rating) # LLM-graded score, 0
|
|
98
|
-
print(report.cosine_similarity) # embedding cosine, 0
|
|
99
|
-
print(report.jaccard_similarity) # token-set overlap, 0
|
|
99
|
+
print(report.average_rating) # LLM-graded score, 0-10
|
|
100
|
+
print(report.cosine_similarity) # embedding cosine, 0-1 (None if not enabled)
|
|
101
|
+
print(report.jaccard_similarity) # token-set overlap, 0-1 (None if not enabled)
|
|
100
102
|
|
|
101
103
|
print(report.summary) # AI-generated narrative from .analyze()
|
|
102
104
|
print(report.recommendations) # list of prioritized, actionable fixes
|
|
@@ -120,7 +122,7 @@ client.evaluations.run(
|
|
|
120
122
|
|
|
121
123
|
See [Prompt registry](EVALUATIONS.md#prompt-registry) in the full guide, or [self-host's docs](https://docs.agentx.so/improve/prompt-management) for the "Suggest improvement" dashboard flow (self-host only - no hosted-SaaS equivalent yet).
|
|
122
124
|
|
|
123
|
-
On self-host, a finalized run can also **gate a CI job**: `run.gate(fail_under=7, no_regression=True)` (on the run context `.execute()` returns) checks the run's average rating against an absolute floor and/or the dataset's previous run, prints per-check verdicts into the CI log, and returns
|
|
125
|
+
On self-host, a finalized run can also **gate a CI job**: `run.gate(fail_under=7, no_regression=True)` (on the run context `.execute()` returns) checks the run's average rating against an absolute floor and/or the dataset's previous run, prints per-check verdicts into the CI log, and returns a `GateResult` - `sys.exit(gate.exit_code)` blocks the merge on regression. Recorded gates appear in the dashboard's CI Gates tab. See [self-host's CI docs](https://docs.agentx.so/integrations/self-host-ci) for the GitHub Actions recipe.
|
|
124
126
|
|
|
125
127
|
See **[EVALUATIONS.md](EVALUATIONS.md)** for the full guide - dataset builder, framework adapters, similarity metrics, smoke testing, judge configuration, prompt registry, and the complete API reference.
|
|
126
128
|
|
|
@@ -188,6 +190,10 @@ extra:
|
|
|
188
190
|
| LlamaIndex | `pip install "agentx-python[llamaindex]"` | `AgentXLlamaIndexHandler` |
|
|
189
191
|
| AutoGen | `pip install "agentx-python[autogen]"` | `AgentXAutoGenObserver` |
|
|
190
192
|
|
|
193
|
+
Two more platforms are covered by **pull importers** rather than in-process hooks, each with its
|
|
194
|
+
own CLI: `agentx-moveworks` (Moveworks Data API sync, no extra needed) and `agentx-databricks`
|
|
195
|
+
(`pip install "agentx-python[databricks]"`, MLflow/Databricks trace sync).
|
|
196
|
+
|
|
191
197
|
Or plain Python - wrap any function with `@tracer.trace(...)` and it just works, no framework
|
|
192
198
|
required. Tracing is **platform agnostic**: each integration stamps its platform label
|
|
193
199
|
automatically, a plain trace auto-detects the one orchestration framework imported in the
|
|
@@ -228,12 +234,14 @@ for signal in client.monitor.signals.list(severity="high"):
|
|
|
228
234
|
print(signal.summary, signal.occurrence_count)
|
|
229
235
|
```
|
|
230
236
|
|
|
231
|
-
Per-agent
|
|
237
|
+
Per-agent monitoring settings (enable/disable, detection categories, notification channels) are `client.monitor.profile.get()`/`.update()`:
|
|
232
238
|
|
|
233
239
|
```python
|
|
234
|
-
client.monitor.profile.update("agent_123",
|
|
240
|
+
client.monitor.profile.update("agent_123", info_detection_enabled=False)
|
|
235
241
|
```
|
|
236
242
|
|
|
243
|
+
On self-host, coverage mode, sample rate, retention, and the built-in latency threshold are project-level defaults set in the dashboard's Platform Settings; `update()` still accepts them for wire compatibility, but only the per-agent fields above take effect there.
|
|
244
|
+
|
|
237
245
|
Self-host also has **online evaluators**: a real LLM judge scoring a sample of live traffic continuously, distinct from a pattern's rule-matching. A score below `alert_threshold` raises a signal the same way a failing pattern does, deduped and triage-ready in `client.monitor.signals`.
|
|
238
246
|
|
|
239
247
|
```python
|
|
@@ -307,7 +315,7 @@ export AGENTX_API_BASE_URL=http://localhost:4700/api/v1
|
|
|
307
315
|
export AGENTX_API_KEY=<printed by agentx-trace-eval on first run>
|
|
308
316
|
```
|
|
309
317
|
|
|
310
|
-
`agentx-trace-eval` isn't this SDK's own code - the engine itself is a separate, compiled binary, downloaded on demand rather than bundled into this package, so installing `agentx-python` doesn't get any heavier for the (much more common) case of just talking to the hosted AgentX API. See that repo's README for what's included, and `AGENTX_INSTALL_DIR`/`AGENTX_TRACE_EVAL_VERSION`/`AGENTX_TRACE_EVAL_SKIP_WEB` env vars to control where/what it installs.
|
|
318
|
+
`agentx-trace-eval` isn't this SDK's own code - the engine itself is a separate, compiled binary, downloaded on demand rather than bundled into this package, so installing `agentx-python` doesn't get any heavier for the (much more common) case of just talking to the hosted AgentX API. Each SDK release pins the engine release it was tested against and converges the install to that pin, so upgrading the SDK upgrades the engine too. Two flags to know: `--update` (consumed by this launcher) force-reinstalls the resolved engine release, while `--upgrade` passes through to `agentx-server` and re-downloads the dashboard bundle before serving. See that repo's README for what's included, and the `AGENTX_INSTALL_DIR`/`AGENTX_TRACE_EVAL_VERSION`/`AGENTX_TRACE_EVAL_SKIP_WEB` env vars to control where/what it installs.
|
|
311
319
|
|
|
312
320
|
---
|
|
313
321
|
|
|
@@ -14,7 +14,7 @@ Or as a context manager around your own kickoff::
|
|
|
14
14
|
result = crew.kickoff(inputs={"topic": "AI"})
|
|
15
15
|
span.output = result.raw
|
|
16
16
|
|
|
17
|
-
Requires: ``pip install agentx[crewai]``
|
|
17
|
+
Requires: ``pip install "agentx-python[crewai]"``
|
|
18
18
|
"""
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
VERSION = "0.8.
|
|
1
|
+
VERSION = "0.8.14"
|
|
2
2
|
|
|
3
3
|
# The AgentX-trace-eval release this SDK version is tested against - what `agentx-trace-eval`
|
|
4
4
|
# installs and converges to (see agentx/cli.py). Bump together with VERSION when releasing, so
|
|
5
5
|
# every published SDK names a known-good engine+dashboard pair. Users can override with
|
|
6
6
|
# AGENTX_TRACE_EVAL_VERSION=<tag|latest>.
|
|
7
|
-
ENGINE_VERSION = "v0.3.
|
|
7
|
+
ENGINE_VERSION = "v0.3.10"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentx-python
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.14
|
|
4
4
|
Summary: Official Python SDK for AgentX (https://www.agentx.so/)
|
|
5
5
|
Home-page: https://github.com/AgentX-ai/AgentX-python
|
|
6
6
|
Author: Robin Wang and AgentX Team
|
|
@@ -8,7 +8,7 @@ Author-email: contact@agentx.so
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
14
|
Requires-Dist: urllib3>=1.26.11
|
|
@@ -50,6 +50,7 @@ Requires-Dist: litellm>=1.0.0; extra == "all"
|
|
|
50
50
|
Requires-Dist: llama-index-core>=0.10.0; extra == "all"
|
|
51
51
|
Requires-Dist: autogen-agentchat>=0.4.0; extra == "all"
|
|
52
52
|
Requires-Dist: autogen-core>=0.4.0; extra == "all"
|
|
53
|
+
Requires-Dist: mlflow>=3.6.0; extra == "all"
|
|
53
54
|
Dynamic: author
|
|
54
55
|
Dynamic: author-email
|
|
55
56
|
Dynamic: classifier
|
|
@@ -109,12 +110,14 @@ pip install --upgrade agentx-python
|
|
|
109
110
|
|
|
110
111
|
Requires Python 3.9 or newer.
|
|
111
112
|
|
|
112
|
-
#### Run self
|
|
113
|
+
#### Run the self-host governance suite locally
|
|
113
114
|
|
|
114
|
-
```
|
|
115
|
-
agentx-trace-eval --dev
|
|
115
|
+
```bash
|
|
116
|
+
agentx-trace-eval --dev
|
|
116
117
|
```
|
|
117
118
|
|
|
119
|
+
(See [Self-host](#self-host) below for what this downloads and how to point the SDK at it.)
|
|
120
|
+
|
|
118
121
|
---
|
|
119
122
|
|
|
120
123
|
## Quick start
|
|
@@ -137,7 +140,7 @@ report = (
|
|
|
137
140
|
.analyze()
|
|
138
141
|
)
|
|
139
142
|
|
|
140
|
-
print(report.average_rating) # LLM-graded score, 0
|
|
143
|
+
print(report.average_rating) # LLM-graded score, 0-10
|
|
141
144
|
print(report.summary) # AI-generated narrative from .analyze()
|
|
142
145
|
```
|
|
143
146
|
|
|
@@ -158,9 +161,9 @@ report = (
|
|
|
158
161
|
.analyze()
|
|
159
162
|
)
|
|
160
163
|
|
|
161
|
-
print(report.average_rating) # LLM-graded score, 0
|
|
162
|
-
print(report.cosine_similarity) # embedding cosine, 0
|
|
163
|
-
print(report.jaccard_similarity) # token-set overlap, 0
|
|
164
|
+
print(report.average_rating) # LLM-graded score, 0-10
|
|
165
|
+
print(report.cosine_similarity) # embedding cosine, 0-1 (None if not enabled)
|
|
166
|
+
print(report.jaccard_similarity) # token-set overlap, 0-1 (None if not enabled)
|
|
164
167
|
|
|
165
168
|
print(report.summary) # AI-generated narrative from .analyze()
|
|
166
169
|
print(report.recommendations) # list of prioritized, actionable fixes
|
|
@@ -184,7 +187,7 @@ client.evaluations.run(
|
|
|
184
187
|
|
|
185
188
|
See [Prompt registry](EVALUATIONS.md#prompt-registry) in the full guide, or [self-host's docs](https://docs.agentx.so/improve/prompt-management) for the "Suggest improvement" dashboard flow (self-host only - no hosted-SaaS equivalent yet).
|
|
186
189
|
|
|
187
|
-
On self-host, a finalized run can also **gate a CI job**: `run.gate(fail_under=7, no_regression=True)` (on the run context `.execute()` returns) checks the run's average rating against an absolute floor and/or the dataset's previous run, prints per-check verdicts into the CI log, and returns
|
|
190
|
+
On self-host, a finalized run can also **gate a CI job**: `run.gate(fail_under=7, no_regression=True)` (on the run context `.execute()` returns) checks the run's average rating against an absolute floor and/or the dataset's previous run, prints per-check verdicts into the CI log, and returns a `GateResult` - `sys.exit(gate.exit_code)` blocks the merge on regression. Recorded gates appear in the dashboard's CI Gates tab. See [self-host's CI docs](https://docs.agentx.so/integrations/self-host-ci) for the GitHub Actions recipe.
|
|
188
191
|
|
|
189
192
|
See **[EVALUATIONS.md](EVALUATIONS.md)** for the full guide - dataset builder, framework adapters, similarity metrics, smoke testing, judge configuration, prompt registry, and the complete API reference.
|
|
190
193
|
|
|
@@ -252,6 +255,10 @@ extra:
|
|
|
252
255
|
| LlamaIndex | `pip install "agentx-python[llamaindex]"` | `AgentXLlamaIndexHandler` |
|
|
253
256
|
| AutoGen | `pip install "agentx-python[autogen]"` | `AgentXAutoGenObserver` |
|
|
254
257
|
|
|
258
|
+
Two more platforms are covered by **pull importers** rather than in-process hooks, each with its
|
|
259
|
+
own CLI: `agentx-moveworks` (Moveworks Data API sync, no extra needed) and `agentx-databricks`
|
|
260
|
+
(`pip install "agentx-python[databricks]"`, MLflow/Databricks trace sync).
|
|
261
|
+
|
|
255
262
|
Or plain Python - wrap any function with `@tracer.trace(...)` and it just works, no framework
|
|
256
263
|
required. Tracing is **platform agnostic**: each integration stamps its platform label
|
|
257
264
|
automatically, a plain trace auto-detects the one orchestration framework imported in the
|
|
@@ -292,12 +299,14 @@ for signal in client.monitor.signals.list(severity="high"):
|
|
|
292
299
|
print(signal.summary, signal.occurrence_count)
|
|
293
300
|
```
|
|
294
301
|
|
|
295
|
-
Per-agent
|
|
302
|
+
Per-agent monitoring settings (enable/disable, detection categories, notification channels) are `client.monitor.profile.get()`/`.update()`:
|
|
296
303
|
|
|
297
304
|
```python
|
|
298
|
-
client.monitor.profile.update("agent_123",
|
|
305
|
+
client.monitor.profile.update("agent_123", info_detection_enabled=False)
|
|
299
306
|
```
|
|
300
307
|
|
|
308
|
+
On self-host, coverage mode, sample rate, retention, and the built-in latency threshold are project-level defaults set in the dashboard's Platform Settings; `update()` still accepts them for wire compatibility, but only the per-agent fields above take effect there.
|
|
309
|
+
|
|
301
310
|
Self-host also has **online evaluators**: a real LLM judge scoring a sample of live traffic continuously, distinct from a pattern's rule-matching. A score below `alert_threshold` raises a signal the same way a failing pattern does, deduped and triage-ready in `client.monitor.signals`.
|
|
302
311
|
|
|
303
312
|
```python
|
|
@@ -371,7 +380,7 @@ export AGENTX_API_BASE_URL=http://localhost:4700/api/v1
|
|
|
371
380
|
export AGENTX_API_KEY=<printed by agentx-trace-eval on first run>
|
|
372
381
|
```
|
|
373
382
|
|
|
374
|
-
`agentx-trace-eval` isn't this SDK's own code - the engine itself is a separate, compiled binary, downloaded on demand rather than bundled into this package, so installing `agentx-python` doesn't get any heavier for the (much more common) case of just talking to the hosted AgentX API. See that repo's README for what's included, and `AGENTX_INSTALL_DIR`/`AGENTX_TRACE_EVAL_VERSION`/`AGENTX_TRACE_EVAL_SKIP_WEB` env vars to control where/what it installs.
|
|
383
|
+
`agentx-trace-eval` isn't this SDK's own code - the engine itself is a separate, compiled binary, downloaded on demand rather than bundled into this package, so installing `agentx-python` doesn't get any heavier for the (much more common) case of just talking to the hosted AgentX API. Each SDK release pins the engine release it was tested against and converges the install to that pin, so upgrading the SDK upgrades the engine too. Two flags to know: `--update` (consumed by this launcher) force-reinstalls the resolved engine release, while `--upgrade` passes through to `agentx-server` and re-downloads the dashboard bundle before serving. See that repo's README for what's included, and the `AGENTX_INSTALL_DIR`/`AGENTX_TRACE_EVAL_VERSION`/`AGENTX_TRACE_EVAL_SKIP_WEB` env vars to control where/what it installs.
|
|
375
384
|
|
|
376
385
|
---
|
|
377
386
|
|
|
@@ -70,6 +70,7 @@ setup(
|
|
|
70
70
|
"llama-index-core>=0.10.0",
|
|
71
71
|
"autogen-agentchat>=0.4.0",
|
|
72
72
|
"autogen-core>=0.4.0",
|
|
73
|
+
"mlflow>=3.6.0",
|
|
73
74
|
],
|
|
74
75
|
},
|
|
75
76
|
author="Robin Wang and AgentX Team",
|
|
@@ -83,5 +84,5 @@ setup(
|
|
|
83
84
|
"License :: OSI Approved :: Apache Software License",
|
|
84
85
|
"Operating System :: OS Independent",
|
|
85
86
|
],
|
|
86
|
-
python_requires=">=3.
|
|
87
|
+
python_requires=">=3.9",
|
|
87
88
|
)
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
"""SDK-to-self-host compatibility matrix.
|
|
2
|
+
|
|
3
|
+
Every public SDK surface is exercised against a LIVE self-host engine and must land in
|
|
4
|
+
exactly one of two tables:
|
|
5
|
+
|
|
6
|
+
- SELF_HOST: the surface must answer without raising. Any exception fails the test with
|
|
7
|
+
the surface's name, so a "fictional" surface (one the engine never grew) can't ship.
|
|
8
|
+
- HOSTED_ONLY: the surface must KEEP failing against the engine AND carry a documented
|
|
9
|
+
reason (plus a docs-file banner that says so). If the engine grows the surface, the
|
|
10
|
+
test fails loudly telling us to promote the entry to SELF_HOST.
|
|
11
|
+
|
|
12
|
+
Opt-in, like the engine's own backend suites: the whole module skips unless both env
|
|
13
|
+
vars below are set.
|
|
14
|
+
|
|
15
|
+
How to run:
|
|
16
|
+
1. Boot a scratch engine (any free port, throwaway home dir):
|
|
17
|
+
cd AgentX-trace-eval/engine
|
|
18
|
+
PORT=4799 AGENTX_HOME=$(mktemp -d) yarn dev
|
|
19
|
+
2. Copy the "Default project API key: agtx_local_..." line from its startup log.
|
|
20
|
+
3. Run the suite:
|
|
21
|
+
AGENTX_COMPAT_BASE_URL=http://localhost:4799/api/v1 \
|
|
22
|
+
AGENTX_COMPAT_API_KEY=agtx_local_... \
|
|
23
|
+
pytest tests/test_selfhost_compat.py -q
|
|
24
|
+
|
|
25
|
+
The scratch engine usually has no judge/provider keys. That is fine and deliberate:
|
|
26
|
+
judge-dependent steps (eval-run scoring) then record results as skipped/unrated, and this
|
|
27
|
+
suite only asserts that every surface ANSWERS, never that the judge liked the answer.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import os
|
|
33
|
+
import time
|
|
34
|
+
import uuid
|
|
35
|
+
from pathlib import Path
|
|
36
|
+
|
|
37
|
+
import pytest
|
|
38
|
+
|
|
39
|
+
BASE_URL = os.getenv("AGENTX_COMPAT_BASE_URL")
|
|
40
|
+
API_KEY = os.getenv("AGENTX_COMPAT_API_KEY")
|
|
41
|
+
|
|
42
|
+
pytestmark = pytest.mark.skipif(
|
|
43
|
+
not (BASE_URL and API_KEY),
|
|
44
|
+
reason="self-host compat suite is opt-in: set AGENTX_COMPAT_BASE_URL and AGENTX_COMPAT_API_KEY",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _tag() -> str:
|
|
51
|
+
return uuid.uuid4().hex[:8]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# ---------------------------------------------------------------------------
|
|
55
|
+
# Shared state: one client, plus lazily created artifacts (a sync trace, one
|
|
56
|
+
# full eval run) reused across parametrized tests so the suite stays fast.
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class CompatContext:
|
|
61
|
+
def __init__(self) -> None:
|
|
62
|
+
# Quiet the runner's interactive spinner/banner in test output.
|
|
63
|
+
os.environ.setdefault("AGENTX_EVAL_QUIET", "1")
|
|
64
|
+
from agentx import AgentX
|
|
65
|
+
|
|
66
|
+
self.client = AgentX(api_key=API_KEY, base_url=BASE_URL)
|
|
67
|
+
self.session_id = f"compat-{_tag()}"
|
|
68
|
+
self._trace_id: str | None = None
|
|
69
|
+
self._eval: dict | None = None
|
|
70
|
+
self.created_dataset_ids: list[str] = []
|
|
71
|
+
|
|
72
|
+
# -- lazy shared artifacts ------------------------------------------------
|
|
73
|
+
|
|
74
|
+
def trace_id(self) -> str:
|
|
75
|
+
"""One sync-ingested trace, created on first use (sync=True so the id exists)."""
|
|
76
|
+
if self._trace_id is None:
|
|
77
|
+
with self.client.tracer.trace(
|
|
78
|
+
"compat-check-agent",
|
|
79
|
+
input={"query": "compat ping"},
|
|
80
|
+
session_id=self.session_id,
|
|
81
|
+
sync=True,
|
|
82
|
+
monitor=False,
|
|
83
|
+
) as span:
|
|
84
|
+
span.output = "compat pong"
|
|
85
|
+
assert span.trace_id, "tracer.trace(sync=True) exited without a trace_id"
|
|
86
|
+
self._trace_id = span.trace_id
|
|
87
|
+
return self._trace_id
|
|
88
|
+
|
|
89
|
+
def eval_artifacts(self) -> dict:
|
|
90
|
+
"""One full evaluation lifecycle, run once: dataset publish -> init_run (via
|
|
91
|
+
client.evaluations.run) -> execute/submit one result -> finalize -> gate.
|
|
92
|
+
A keyless engine records the result unrated; every surface must still answer."""
|
|
93
|
+
if self._eval is None:
|
|
94
|
+
ds = (
|
|
95
|
+
self.client.evaluations.datasets.builder(
|
|
96
|
+
name=f"compat-ds-{_tag()}",
|
|
97
|
+
description="scratch dataset for the self-host compat matrix",
|
|
98
|
+
)
|
|
99
|
+
.add_case("What is 2 + 2?", expected_results="4")
|
|
100
|
+
.publish()
|
|
101
|
+
)
|
|
102
|
+
self.created_dataset_ids.append(ds.id)
|
|
103
|
+
run_ctx = self.client.evaluations.run(
|
|
104
|
+
ds.id, {"kind": "custom_agent", "displayName": "compat-check"}
|
|
105
|
+
)
|
|
106
|
+
run_ctx.execute(lambda case: "4")
|
|
107
|
+
run_ctx.finalize()
|
|
108
|
+
gate = run_ctx.gate(fail_under=0.0)
|
|
109
|
+
self._eval = {"dataset_id": ds.id, "run_id": run_ctx.run_id, "gate": gate}
|
|
110
|
+
return self._eval
|
|
111
|
+
|
|
112
|
+
# -- cleanup --------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
def cleanup(self) -> None:
|
|
115
|
+
for dataset_id in self.created_dataset_ids:
|
|
116
|
+
try:
|
|
117
|
+
self.client.evaluations.datasets.delete(dataset_id)
|
|
118
|
+
except Exception:
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@pytest.fixture(scope="module")
|
|
123
|
+
def compat():
|
|
124
|
+
ctx = CompatContext()
|
|
125
|
+
yield ctx
|
|
126
|
+
ctx.cleanup()
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# ---------------------------------------------------------------------------
|
|
130
|
+
# SELF_HOST checks - each must answer without raising
|
|
131
|
+
# ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _check_ping(ctx: CompatContext) -> None:
|
|
135
|
+
result = ctx.client.ping()
|
|
136
|
+
assert result.get("ok") is True
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _check_tracer_sync_trace_and_flush(ctx: CompatContext) -> None:
|
|
140
|
+
assert ctx.trace_id()
|
|
141
|
+
assert ctx.client.tracer.flush(timeout=10) is True
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _check_traces_get(ctx: CompatContext) -> None:
|
|
145
|
+
detail = ctx.client.traces.get(ctx.trace_id())
|
|
146
|
+
assert isinstance(detail, dict) and detail
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _check_traces_list(ctx: CompatContext) -> None:
|
|
150
|
+
ctx.trace_id() # make sure at least one trace exists
|
|
151
|
+
page = ctx.client.traces.list(limit=5)
|
|
152
|
+
assert isinstance(page.get("traces"), list) and page["traces"]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _check_monitor_kpis(ctx: CompatContext) -> None:
|
|
156
|
+
assert isinstance(ctx.client.monitor.kpis(), dict)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _check_monitor_metrics(ctx: CompatContext) -> None:
|
|
160
|
+
assert isinstance(ctx.client.monitor.metrics(window="1h"), dict)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _check_monitor_topics(ctx: CompatContext) -> None:
|
|
164
|
+
assert isinstance(ctx.client.monitor.topics(), dict)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _check_monitor_list_agents(ctx: CompatContext) -> None:
|
|
168
|
+
ctx.trace_id() # tracing auto-creates the agent
|
|
169
|
+
agents = ctx.client.monitor.list_agents()
|
|
170
|
+
assert isinstance(agents, list)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _check_monitor_patterns(ctx: CompatContext) -> None:
|
|
174
|
+
# builder + publish + get + list. The SDK exposes no pattern delete, so the
|
|
175
|
+
# published pattern stays behind on the scratch engine (throwaway by design).
|
|
176
|
+
pattern = ctx.client.monitor.patterns.builder(
|
|
177
|
+
name=f"compat-pattern-{_tag()}",
|
|
178
|
+
detector_kind="contains",
|
|
179
|
+
include_terms=["compat-term-that-never-matches"],
|
|
180
|
+
enabled=False,
|
|
181
|
+
).publish()
|
|
182
|
+
assert pattern.id
|
|
183
|
+
assert ctx.client.monitor.patterns.get(pattern.id).id == pattern.id
|
|
184
|
+
assert any(p.id == pattern.id for p in ctx.client.monitor.patterns.list())
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _check_monitor_judge_scorers_round_trip(ctx: CompatContext) -> None:
|
|
188
|
+
scorer = ctx.client.monitor.judge_scorers.builder(
|
|
189
|
+
name=f"compat-scorer-{_tag()}",
|
|
190
|
+
acceptance_criteria="The answer is correct.",
|
|
191
|
+
).publish()
|
|
192
|
+
try:
|
|
193
|
+
assert ctx.client.monitor.judge_scorers.get(scorer.id).id == scorer.id
|
|
194
|
+
updated = ctx.client.monitor.judge_scorers.update(
|
|
195
|
+
scorer.id,
|
|
196
|
+
online={"enabled": False, "sampleRate": 0.1, "alertThreshold": 5},
|
|
197
|
+
)
|
|
198
|
+
assert updated.id == scorer.id
|
|
199
|
+
finally:
|
|
200
|
+
ctx.client.monitor.judge_scorers.delete(scorer.id)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _check_monitor_scorers_list(ctx: CompatContext) -> None:
|
|
204
|
+
assert isinstance(ctx.client.monitor.scorers.list(), list)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _check_monitor_review_queue_list(ctx: CompatContext) -> None:
|
|
208
|
+
assert isinstance(ctx.client.monitor.review_queue.list(status="all"), list)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _check_monitor_rules_list(ctx: CompatContext) -> None:
|
|
212
|
+
assert isinstance(ctx.client.monitor.rules.list(), list)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _check_monitor_sessions_spans(ctx: CompatContext) -> None:
|
|
216
|
+
ctx.trace_id() # ingests one span into ctx.session_id
|
|
217
|
+
spans = ctx.client.monitor.sessions.spans(ctx.session_id)
|
|
218
|
+
assert isinstance(spans, list) and spans
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _check_evaluations_dataset_round_trip(ctx: CompatContext) -> None:
|
|
222
|
+
ds = (
|
|
223
|
+
ctx.client.evaluations.datasets.builder(
|
|
224
|
+
name=f"compat-ds-roundtrip-{_tag()}",
|
|
225
|
+
description="round-trip dataset (deleted by this test)",
|
|
226
|
+
)
|
|
227
|
+
.add_case("Name a prime number.", expected_results="Any prime, e.g. 7")
|
|
228
|
+
.publish()
|
|
229
|
+
)
|
|
230
|
+
assert ds.id
|
|
231
|
+
fetched = ctx.client.evaluations.datasets.get(ds.id)
|
|
232
|
+
assert fetched.id == ds.id and len(fetched.questions) == 1
|
|
233
|
+
ctx.client.evaluations.datasets.delete(ds.id)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _check_evaluations_run_lifecycle(ctx: CompatContext) -> None:
|
|
237
|
+
artifacts = ctx.eval_artifacts()
|
|
238
|
+
assert artifacts["run_id"]
|
|
239
|
+
# Keyless judge => unrated results => gate answers but may not pass. Both fine.
|
|
240
|
+
assert isinstance(artifacts["gate"].passed, bool)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _check_evaluations_get_run(ctx: CompatContext) -> None:
|
|
244
|
+
run = ctx.client.evaluations.get_run(ctx.eval_artifacts()["run_id"])
|
|
245
|
+
assert isinstance(run, dict) and run
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _check_evaluations_list_gates(ctx: CompatContext) -> None:
|
|
249
|
+
ctx.eval_artifacts() # records one gate verdict
|
|
250
|
+
assert isinstance(ctx.client.evaluations.list_gates(), list)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _check_evaluations_prompts_registry(ctx: CompatContext) -> None:
|
|
254
|
+
name = f"compat-prompt-{_tag()}"
|
|
255
|
+
created = ctx.client.evaluations.prompts.create(
|
|
256
|
+
name, "You are a compat-check assistant.", description="compat matrix scratch prompt"
|
|
257
|
+
)
|
|
258
|
+
assert created.version >= 1
|
|
259
|
+
fetched = ctx.client.evaluations.prompts.get(name)
|
|
260
|
+
assert fetched.name == name and fetched.text
|
|
261
|
+
assert any(p.name == name for p in ctx.client.evaluations.prompts.list())
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _check_feedback_report(ctx: CompatContext) -> None:
|
|
265
|
+
report = ctx.client.feedback.report(
|
|
266
|
+
trace_id=ctx.trace_id(), rating="up", end_user_id="compat-suite"
|
|
267
|
+
)
|
|
268
|
+
assert isinstance(report, dict)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _check_outcomes_report(ctx: CompatContext) -> None:
|
|
272
|
+
report = ctx.client.outcomes.report(
|
|
273
|
+
trace_id=ctx.trace_id(),
|
|
274
|
+
outcome="confirmed_good",
|
|
275
|
+
is_negative=False,
|
|
276
|
+
reported_by="compat-suite",
|
|
277
|
+
)
|
|
278
|
+
assert isinstance(report, dict)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _check_export_manifest_and_iter(ctx: CompatContext) -> None:
|
|
282
|
+
ctx.trace_id() # at least one exportable row
|
|
283
|
+
manifest = ctx.client.export.manifest()
|
|
284
|
+
assert isinstance(manifest, list) and manifest
|
|
285
|
+
rows = list(ctx.client.export.iter("traces"))
|
|
286
|
+
assert rows and all(isinstance(r, dict) for r in rows)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
SELF_HOST = [
|
|
290
|
+
("client.ping", _check_ping),
|
|
291
|
+
("tracer.trace(sync=True) + tracer.flush", _check_tracer_sync_trace_and_flush),
|
|
292
|
+
("traces.get", _check_traces_get),
|
|
293
|
+
("traces.list", _check_traces_list),
|
|
294
|
+
("monitor.kpis", _check_monitor_kpis),
|
|
295
|
+
("monitor.metrics", _check_monitor_metrics),
|
|
296
|
+
("monitor.topics", _check_monitor_topics),
|
|
297
|
+
("monitor.list_agents", _check_monitor_list_agents),
|
|
298
|
+
("monitor.patterns builder/publish/get/list", _check_monitor_patterns),
|
|
299
|
+
("monitor.judge_scorers create/get/update/delete", _check_monitor_judge_scorers_round_trip),
|
|
300
|
+
("monitor.scorers.list", _check_monitor_scorers_list),
|
|
301
|
+
("monitor.review_queue.list", _check_monitor_review_queue_list),
|
|
302
|
+
("monitor.rules.list", _check_monitor_rules_list),
|
|
303
|
+
("monitor.sessions.spans", _check_monitor_sessions_spans),
|
|
304
|
+
("evaluations.datasets builder/publish/get/delete", _check_evaluations_dataset_round_trip),
|
|
305
|
+
("evaluations run/execute/finalize/gate", _check_evaluations_run_lifecycle),
|
|
306
|
+
("evaluations.get_run", _check_evaluations_get_run),
|
|
307
|
+
("evaluations.list_gates", _check_evaluations_list_gates),
|
|
308
|
+
("evaluations.prompts create/get/list", _check_evaluations_prompts_registry),
|
|
309
|
+
("feedback.report", _check_feedback_report),
|
|
310
|
+
("outcomes.report", _check_outcomes_report),
|
|
311
|
+
("export.manifest + export.iter", _check_export_manifest_and_iter),
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@pytest.mark.parametrize(
|
|
316
|
+
"surface,check", SELF_HOST, ids=[name for name, _ in SELF_HOST]
|
|
317
|
+
)
|
|
318
|
+
def test_self_host_surface(surface, check, compat):
|
|
319
|
+
try:
|
|
320
|
+
check(compat)
|
|
321
|
+
except AssertionError:
|
|
322
|
+
raise
|
|
323
|
+
except Exception as exc:
|
|
324
|
+
pytest.fail(
|
|
325
|
+
f"self-host surface {surface!r} raised {type(exc).__name__}: {exc} "
|
|
326
|
+
"(either the SDK or the engine drifted - this surface is supposed to work "
|
|
327
|
+
"against a self-host engine)"
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# ---------------------------------------------------------------------------
|
|
332
|
+
# HOSTED_ONLY checks - each must KEEP failing against the engine, and the docs
|
|
333
|
+
# must say so. If one starts working, promote it to SELF_HOST above.
|
|
334
|
+
# ---------------------------------------------------------------------------
|
|
335
|
+
|
|
336
|
+
CI_BANNER_NEEDLE = "Hosted platform only."
|
|
337
|
+
CI_ROUTE_NEEDLE = "/ingest/ci-runs"
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def _call_run_eval(ctx: CompatContext):
|
|
341
|
+
return ctx.client.tracer.run_eval("evds_compat_missing", lambda q: "answer")
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def _call_create_ci_run(ctx: CompatContext):
|
|
345
|
+
return ctx.client.tracer.create_ci_run("evds_compat_missing")
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def _call_get_ci_run(ctx: CompatContext):
|
|
349
|
+
return ctx.client.tracer.get_ci_run("cirun_compat_missing")
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _call_finalize_ci_run(ctx: CompatContext):
|
|
353
|
+
return ctx.client.tracer.finalize_ci_run("cirun_compat_missing")
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _call_list_models(ctx: CompatContext):
|
|
357
|
+
return ctx.client.evaluations.list_models()
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
HOSTED_ONLY = [
|
|
361
|
+
(
|
|
362
|
+
"tracer.run_eval",
|
|
363
|
+
_call_run_eval,
|
|
364
|
+
"Targets the hosted /ingest/ci-runs API; the self-host engine does not serve it. "
|
|
365
|
+
"Self-host CI gating is evaluations.run(...).execute(...).finalize().gate(...).",
|
|
366
|
+
"CICD_EVAL.md",
|
|
367
|
+
(CI_BANNER_NEEDLE, CI_ROUTE_NEEDLE),
|
|
368
|
+
),
|
|
369
|
+
(
|
|
370
|
+
"tracer.create_ci_run",
|
|
371
|
+
_call_create_ci_run,
|
|
372
|
+
"Low-level hosted /ingest/ci-runs call; 404 on self-host, surfaced as DatasetNotFound.",
|
|
373
|
+
"CICD_EVAL.md",
|
|
374
|
+
(CI_BANNER_NEEDLE, CI_ROUTE_NEEDLE),
|
|
375
|
+
),
|
|
376
|
+
(
|
|
377
|
+
"tracer.get_ci_run",
|
|
378
|
+
_call_get_ci_run,
|
|
379
|
+
"Low-level hosted /ingest/ci-runs call; 404 on self-host, surfaced as DatasetNotFound.",
|
|
380
|
+
"CICD_EVAL.md",
|
|
381
|
+
(CI_BANNER_NEEDLE, CI_ROUTE_NEEDLE),
|
|
382
|
+
),
|
|
383
|
+
(
|
|
384
|
+
"tracer.finalize_ci_run",
|
|
385
|
+
_call_finalize_ci_run,
|
|
386
|
+
"Low-level hosted /ingest/ci-runs call; 404 on self-host, surfaced as DatasetNotFound.",
|
|
387
|
+
"CICD_EVAL.md",
|
|
388
|
+
(CI_BANNER_NEEDLE, CI_ROUTE_NEEDLE),
|
|
389
|
+
),
|
|
390
|
+
(
|
|
391
|
+
"evaluations.list_models",
|
|
392
|
+
_call_list_models,
|
|
393
|
+
"Targets the hosted /custom-agent-evaluations/models registry; the engine explicitly "
|
|
394
|
+
"has not ported it (engine routes/evaluations.ts: 'Still not ported: list_models').",
|
|
395
|
+
"EVALUATIONS.md",
|
|
396
|
+
("`list_models()` is **hosted platform only**",),
|
|
397
|
+
),
|
|
398
|
+
]
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
@pytest.mark.parametrize(
|
|
402
|
+
"surface,call,reason,doc_file,doc_needles",
|
|
403
|
+
HOSTED_ONLY,
|
|
404
|
+
ids=[name for name, *_ in HOSTED_ONLY],
|
|
405
|
+
)
|
|
406
|
+
def test_hosted_only_surface(surface, call, reason, doc_file, doc_needles, compat):
|
|
407
|
+
assert reason and reason.strip(), f"hosted-only entry {surface!r} must document why"
|
|
408
|
+
|
|
409
|
+
try:
|
|
410
|
+
call(compat)
|
|
411
|
+
except Exception:
|
|
412
|
+
pass # expected: the engine does not serve this surface
|
|
413
|
+
else:
|
|
414
|
+
pytest.fail(
|
|
415
|
+
f"hosted-only surface {surface!r} SUCCEEDED against the self-host engine. "
|
|
416
|
+
"The engine grew this surface: move the entry to SELF_HOST and update the docs."
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
doc_text = (REPO_ROOT / doc_file).read_text(encoding="utf-8")
|
|
420
|
+
for needle in doc_needles:
|
|
421
|
+
assert needle in doc_text, (
|
|
422
|
+
f"hosted-only surface {surface!r}: expected {doc_file} to contain {needle!r} "
|
|
423
|
+
"so the limitation stays documented"
|
|
424
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|