agentx-python 0.6.16__tar.gz → 0.6.17__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.6.16 → agentx_python-0.6.17}/PKG-INFO +12 -3
- {agentx_python-0.6.16 → agentx_python-0.6.17}/README.md +11 -2
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/agentx.py +6 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/client.py +28 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/runner.py +79 -0
- agentx_python-0.6.17/agentx/feedback.py +76 -0
- agentx_python-0.6.17/agentx/version.py +1 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx_python.egg-info/PKG-INFO +12 -3
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx_python.egg-info/SOURCES.txt +1 -0
- agentx_python-0.6.16/agentx/version.py +0 -1
- {agentx_python-0.6.16 → agentx_python-0.6.17}/LICENSE +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/__init__.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/cli.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/__init__.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/_term.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/adapters/__init__.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/adapters/http_endpoint.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/adapters/precomputed.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/adapters/raw.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/datasets.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/evaluation_settings.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/models.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/prompts.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/redaction.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/reporting.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/results.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/evaluations/tracing.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/exceptions.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/__init__.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/_traced_call.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/anthropic.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/autogen.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/crewai.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/google_adk.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/google_genai.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/langchain.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/litellm.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/llamaindex.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/openai.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/integrations/openai_agents.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/monitor/__init__.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/monitor/client.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/monitor/models.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/monitor/online_evaluators.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/monitor/patterns.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/monitor/profile.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/monitor/signals.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/outcomes.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/py.typed +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/resources/__init__.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/resources/agent.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/resources/conversation.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/resources/workforce.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/tracing/__init__.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/tracing/ci_types.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/tracing/ingest_client.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/tracing/tracer.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx/util.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx_python.egg-info/dependency_links.txt +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx_python.egg-info/entry_points.txt +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx_python.egg-info/not-zip-safe +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx_python.egg-info/requires.txt +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/agentx_python.egg-info/top_level.txt +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/setup.cfg +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/setup.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/tests/test_integration.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/tests/test_integrations.py +0 -0
- {agentx_python-0.6.16 → agentx_python-0.6.17}/tests/test_span_tree.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentx-python
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.17
|
|
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
|
|
@@ -189,7 +189,9 @@ client.evaluations.run(
|
|
|
189
189
|
).execute(my_agent_fn)
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
See [Prompt registry](EVALUATIONS.md#prompt-registry) in the full guide, or [self-host's docs](https://docs.agentx.so/
|
|
192
|
+
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).
|
|
193
|
+
|
|
194
|
+
On self-host, a finalized run can also **gate a CI job**: `report.gate(fail_under=7, no_regression=True)` 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 an exit code - `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.
|
|
193
195
|
|
|
194
196
|
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.
|
|
195
197
|
|
|
@@ -311,7 +313,7 @@ evaluator = client.monitor.online_evaluators.builder(
|
|
|
311
313
|
client.monitor.online_evaluators.ratings(evaluator.id, window="7d")
|
|
312
314
|
```
|
|
313
315
|
|
|
314
|
-
An online evaluator can also judge **whole conversations** instead of single traces: pass `scope="session"` and the engine scores each multi-turn session once it's been idle for `idle_seconds`, re-scoring if the conversation resumes. And to close the loop with reality, `client.outcomes.report(...)`
|
|
316
|
+
An online evaluator can also judge **whole conversations** instead of single traces: pass `scope="session"` and the engine scores each multi-turn session once it's been idle for `idle_seconds`, re-scoring if the conversation resumes. And to close the loop with reality, two ground-truth streams feed the dashboard's Judge Calibration view (which measures how often AgentX's automated verdicts agree with what actually happened): `client.outcomes.report(...)` for after-the-fact system results (a reopened ticket, a human confirmation), and `client.feedback.report(...)` for end-user votes forwarded from your own app's UI - a "down" raises a "Negative user feedback" signal directly, no sampling or judge call involved. All self-host features.
|
|
315
317
|
|
|
316
318
|
```python
|
|
317
319
|
client.monitor.online_evaluators.builder(
|
|
@@ -328,6 +330,13 @@ client.outcomes.report(
|
|
|
328
330
|
is_negative=True,
|
|
329
331
|
reason="Customer reopened the ticket within 3 days",
|
|
330
332
|
)
|
|
333
|
+
|
|
334
|
+
client.feedback.report(
|
|
335
|
+
trace_id=trace_id,
|
|
336
|
+
rating="down", # "up" or "down"
|
|
337
|
+
comment="It never answered my question", # optional, the user's own words
|
|
338
|
+
end_user_id=current_user.id, # optional, opaque to AgentX
|
|
339
|
+
)
|
|
331
340
|
```
|
|
332
341
|
|
|
333
342
|
See **[TRACING.md](TRACING.md)** for the complete Monitor guide.
|
|
@@ -127,7 +127,9 @@ client.evaluations.run(
|
|
|
127
127
|
).execute(my_agent_fn)
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
See [Prompt registry](EVALUATIONS.md#prompt-registry) in the full guide, or [self-host's docs](https://docs.agentx.so/
|
|
130
|
+
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).
|
|
131
|
+
|
|
132
|
+
On self-host, a finalized run can also **gate a CI job**: `report.gate(fail_under=7, no_regression=True)` 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 an exit code - `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.
|
|
131
133
|
|
|
132
134
|
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.
|
|
133
135
|
|
|
@@ -249,7 +251,7 @@ evaluator = client.monitor.online_evaluators.builder(
|
|
|
249
251
|
client.monitor.online_evaluators.ratings(evaluator.id, window="7d")
|
|
250
252
|
```
|
|
251
253
|
|
|
252
|
-
An online evaluator can also judge **whole conversations** instead of single traces: pass `scope="session"` and the engine scores each multi-turn session once it's been idle for `idle_seconds`, re-scoring if the conversation resumes. And to close the loop with reality, `client.outcomes.report(...)`
|
|
254
|
+
An online evaluator can also judge **whole conversations** instead of single traces: pass `scope="session"` and the engine scores each multi-turn session once it's been idle for `idle_seconds`, re-scoring if the conversation resumes. And to close the loop with reality, two ground-truth streams feed the dashboard's Judge Calibration view (which measures how often AgentX's automated verdicts agree with what actually happened): `client.outcomes.report(...)` for after-the-fact system results (a reopened ticket, a human confirmation), and `client.feedback.report(...)` for end-user votes forwarded from your own app's UI - a "down" raises a "Negative user feedback" signal directly, no sampling or judge call involved. All self-host features.
|
|
253
255
|
|
|
254
256
|
```python
|
|
255
257
|
client.monitor.online_evaluators.builder(
|
|
@@ -266,6 +268,13 @@ client.outcomes.report(
|
|
|
266
268
|
is_negative=True,
|
|
267
269
|
reason="Customer reopened the ticket within 3 days",
|
|
268
270
|
)
|
|
271
|
+
|
|
272
|
+
client.feedback.report(
|
|
273
|
+
trace_id=trace_id,
|
|
274
|
+
rating="down", # "up" or "down"
|
|
275
|
+
comment="It never answered my question", # optional, the user's own words
|
|
276
|
+
end_user_id=current_user.id, # optional, opaque to AgentX
|
|
277
|
+
)
|
|
269
278
|
```
|
|
270
279
|
|
|
271
280
|
See **[TRACING.md](TRACING.md)** for the complete Monitor guide.
|
|
@@ -60,6 +60,12 @@ class AgentX:
|
|
|
60
60
|
# ground truth behind the dashboard's Judge Calibration card. Self-host only.
|
|
61
61
|
self.outcomes = OutcomesClient(api_key=self.api_key)
|
|
62
62
|
|
|
63
|
+
from agentx.feedback import FeedbackClient
|
|
64
|
+
|
|
65
|
+
# Forward end-user votes ("up"/"down") on traced responses - a "down" raises a signal
|
|
66
|
+
# directly, and every vote feeds Judge Calibration alongside outcomes. Self-host only.
|
|
67
|
+
self.feedback = FeedbackClient(api_key=self.api_key)
|
|
68
|
+
|
|
63
69
|
_ingest_client = IngestClient(
|
|
64
70
|
api_key=self.api_key,
|
|
65
71
|
sdk_version=VERSION,
|
|
@@ -265,6 +265,34 @@ class EvaluationsClient:
|
|
|
265
265
|
"POST", f"/runs/{run_id}/finalize", json={"status": "completed"}
|
|
266
266
|
)
|
|
267
267
|
|
|
268
|
+
def gate_run(
|
|
269
|
+
self,
|
|
270
|
+
run_id: str,
|
|
271
|
+
*,
|
|
272
|
+
fail_under: Optional[float] = None,
|
|
273
|
+
no_regression: bool = False,
|
|
274
|
+
tolerance: Optional[float] = None,
|
|
275
|
+
record: bool = True,
|
|
276
|
+
caller: Optional[str] = "sdk",
|
|
277
|
+
) -> Dict[str, Any]:
|
|
278
|
+
# CI gate (self-host): pass/fail a finalized run against an absolute rating floor and/or
|
|
279
|
+
# the dataset's previous completed run. Recorded into gate history by default (the
|
|
280
|
+
# dashboard's CI page lists these); pass record=False for a preview that leaves no trace.
|
|
281
|
+
# `caller` is a free label shown in that history ("sdk", "github-actions", ...). See
|
|
282
|
+
# EvaluationRunContext.gate() for the CI-facing wrapper with printed verdicts.
|
|
283
|
+
params: Dict[str, Any] = {}
|
|
284
|
+
if fail_under is not None:
|
|
285
|
+
params["failUnder"] = fail_under
|
|
286
|
+
if no_regression:
|
|
287
|
+
params["noRegression"] = "true"
|
|
288
|
+
if tolerance is not None:
|
|
289
|
+
params["tolerance"] = tolerance
|
|
290
|
+
if record:
|
|
291
|
+
params["record"] = "true"
|
|
292
|
+
if caller:
|
|
293
|
+
params["caller"] = caller
|
|
294
|
+
return self._request("GET", f"/runs/{run_id}/gate", params=params)
|
|
295
|
+
|
|
268
296
|
def analyze_run(
|
|
269
297
|
self,
|
|
270
298
|
run_id: str,
|
|
@@ -55,6 +55,23 @@ _ANALYSIS_LEVEL_LABELS = {
|
|
|
55
55
|
_DEFAULT_JUDGE_MODEL = "gpt-5.5"
|
|
56
56
|
|
|
57
57
|
|
|
58
|
+
class GateResult:
|
|
59
|
+
"""Wire result of the CI gate (GET /runs/:id/gate) with attribute access for the fields a
|
|
60
|
+
CI script actually branches on."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, data: Dict[str, Any]):
|
|
63
|
+
self.raw = data
|
|
64
|
+
self.passed: bool = bool(data.get("passed"))
|
|
65
|
+
self.average_rating: Optional[float] = data.get("averageRating")
|
|
66
|
+
self.baseline_average: Optional[float] = data.get("baselineAverage")
|
|
67
|
+
self.baseline_run_id: Optional[str] = data.get("baselineRunId")
|
|
68
|
+
self.checks: List[Dict[str, Any]] = data.get("checks", [])
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def exit_code(self) -> int:
|
|
72
|
+
return 0 if self.passed else 1
|
|
73
|
+
|
|
74
|
+
|
|
58
75
|
class EvaluationRunContext:
|
|
59
76
|
"""
|
|
60
77
|
Fluent builder returned by client.evaluations.run(...).
|
|
@@ -210,6 +227,42 @@ class EvaluationRunContext:
|
|
|
210
227
|
logger.error("Finalize failed: %s", exc)
|
|
211
228
|
return self
|
|
212
229
|
|
|
230
|
+
def gate(
|
|
231
|
+
self,
|
|
232
|
+
*,
|
|
233
|
+
fail_under: Optional[float] = None,
|
|
234
|
+
no_regression: bool = False,
|
|
235
|
+
tolerance: Optional[float] = None,
|
|
236
|
+
caller: str = "sdk",
|
|
237
|
+
) -> "GateResult":
|
|
238
|
+
"""CI gate (self-host): pass/fail this finalized run so a CI job can block a merge.
|
|
239
|
+
|
|
240
|
+
``fail_under`` fails the gate when the run's average rating is below the floor;
|
|
241
|
+
``no_regression=True`` fails it when the average dropped more than ``tolerance``
|
|
242
|
+
(default 0.5, judge scores are noisy) below the dataset's previous completed run.
|
|
243
|
+
At least one check is required. Prints a CI-log-friendly verdict and returns a
|
|
244
|
+
:class:`GateResult` - the caller decides the exit code::
|
|
245
|
+
|
|
246
|
+
report = client.evaluations.run(...).execute(my_agent).finalize()
|
|
247
|
+
gate = report.gate(fail_under=7, no_regression=True)
|
|
248
|
+
if not gate.passed:
|
|
249
|
+
sys.exit(1)
|
|
250
|
+
"""
|
|
251
|
+
data = self._client.gate_run(
|
|
252
|
+
self._run.run_id,
|
|
253
|
+
fail_under=fail_under,
|
|
254
|
+
no_regression=no_regression,
|
|
255
|
+
tolerance=tolerance,
|
|
256
|
+
caller=caller,
|
|
257
|
+
)
|
|
258
|
+
result = GateResult(data)
|
|
259
|
+
print()
|
|
260
|
+
for check in result.checks:
|
|
261
|
+
mark = green("✓") if check.get("passed") else red("✗")
|
|
262
|
+
print(f" {mark} [{check.get('check')}] {check.get('detail')}")
|
|
263
|
+
print(f" {green('✓ GATE PASSED') if result.passed else red('✗ GATE FAILED')}")
|
|
264
|
+
return result
|
|
265
|
+
|
|
213
266
|
# ------------------------------------------------------------------
|
|
214
267
|
# Live rating stats - server-computed (Evaluate.liveStatistics), refreshed
|
|
215
268
|
# from the response of each append_results()/finalize_run() call. Available
|
|
@@ -350,6 +403,32 @@ class EvaluationsRunner:
|
|
|
350
403
|
script execution)."""
|
|
351
404
|
return self._client.get_analysis_status(run_id)
|
|
352
405
|
|
|
406
|
+
def gate_run(
|
|
407
|
+
self,
|
|
408
|
+
run_id: str,
|
|
409
|
+
*,
|
|
410
|
+
fail_under: Optional[float] = None,
|
|
411
|
+
no_regression: bool = False,
|
|
412
|
+
tolerance: Optional[float] = None,
|
|
413
|
+
record: bool = True,
|
|
414
|
+
caller: Optional[str] = "sdk",
|
|
415
|
+
) -> GateResult:
|
|
416
|
+
"""CI-gate any finalized run by id - the standalone form of
|
|
417
|
+
``EvaluationRunContext.gate()``, for gating a run created elsewhere or
|
|
418
|
+
re-checking one without re-running it (self-host only). Pass
|
|
419
|
+
``record=False`` for a check that stays out of the dashboard's CI Gates
|
|
420
|
+
history."""
|
|
421
|
+
return GateResult(
|
|
422
|
+
self._client.gate_run(
|
|
423
|
+
run_id,
|
|
424
|
+
fail_under=fail_under,
|
|
425
|
+
no_regression=no_regression,
|
|
426
|
+
tolerance=tolerance,
|
|
427
|
+
record=record,
|
|
428
|
+
caller=caller,
|
|
429
|
+
)
|
|
430
|
+
)
|
|
431
|
+
|
|
353
432
|
def run(
|
|
354
433
|
self,
|
|
355
434
|
dataset_id: str,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from agentx.util import api_base, get_headers
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AgentXFeedbackError(Exception):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FeedbackClient:
|
|
18
|
+
"""Surfaced as ``client.feedback``: forward an END USER's reaction to a traced response
|
|
19
|
+
(self-host only, ``POST /feedback``) - the vote button in your own app's UI, relayed to
|
|
20
|
+
AgentX. The cheapest ground truth there is: a "down" raises a "Negative user feedback"
|
|
21
|
+
signal directly (the user is the detector, no sampling or judge call), and every report
|
|
22
|
+
also feeds Judge Calibration, so AgentX's automated verdicts get measured against real
|
|
23
|
+
human reactions.
|
|
24
|
+
|
|
25
|
+
Distinct from ``client.outcomes``: an outcome is an after-the-fact SYSTEM result ("ticket
|
|
26
|
+
reopened", reported by a workflow); feedback is a human vote with up/down semantics.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, api_key: Optional[str] = None):
|
|
30
|
+
self._api_key = api_key
|
|
31
|
+
|
|
32
|
+
def report(
|
|
33
|
+
self,
|
|
34
|
+
trace_id: str,
|
|
35
|
+
rating: str,
|
|
36
|
+
*,
|
|
37
|
+
comment: Optional[str] = None,
|
|
38
|
+
end_user_id: Optional[str] = None,
|
|
39
|
+
) -> Dict[str, Any]:
|
|
40
|
+
"""Report one end-user vote on a trace.
|
|
41
|
+
|
|
42
|
+
``rating`` is ``"up"`` or ``"down"``. ``comment`` is the user's own words, if your UI
|
|
43
|
+
collects them (a "down" comment becomes the signal's summary and improvement evidence).
|
|
44
|
+
``end_user_id`` is your app's identifier for the voter, kept opaque by AgentX.
|
|
45
|
+
|
|
46
|
+
Example, from your app's vote handler::
|
|
47
|
+
|
|
48
|
+
client.feedback.report(
|
|
49
|
+
trace_id=trace_id,
|
|
50
|
+
rating="down",
|
|
51
|
+
comment="It never answered my question",
|
|
52
|
+
end_user_id=current_user.id,
|
|
53
|
+
)
|
|
54
|
+
"""
|
|
55
|
+
if rating not in ("up", "down"):
|
|
56
|
+
raise AgentXFeedbackError('rating must be "up" or "down"')
|
|
57
|
+
payload: Dict[str, Any] = {"traceId": trace_id, "rating": rating}
|
|
58
|
+
if comment:
|
|
59
|
+
payload["comment"] = comment
|
|
60
|
+
if end_user_id:
|
|
61
|
+
payload["endUserId"] = end_user_id
|
|
62
|
+
|
|
63
|
+
resp = requests.post(
|
|
64
|
+
f"{api_base()}/feedback",
|
|
65
|
+
headers={**get_headers(self._api_key), "Content-Type": "application/json"},
|
|
66
|
+
json=payload,
|
|
67
|
+
timeout=10,
|
|
68
|
+
)
|
|
69
|
+
if resp.status_code >= 400:
|
|
70
|
+
try:
|
|
71
|
+
detail = resp.json().get("error", resp.reason)
|
|
72
|
+
except ValueError:
|
|
73
|
+
detail = resp.reason
|
|
74
|
+
raise AgentXFeedbackError(f"Failed to report feedback ({resp.status_code}): {detail}")
|
|
75
|
+
logger.info("Reported %s feedback on trace %s", rating, trace_id)
|
|
76
|
+
return resp.json().get("feedback", {})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION = "0.6.17"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentx-python
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.17
|
|
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
|
|
@@ -189,7 +189,9 @@ client.evaluations.run(
|
|
|
189
189
|
).execute(my_agent_fn)
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
See [Prompt registry](EVALUATIONS.md#prompt-registry) in the full guide, or [self-host's docs](https://docs.agentx.so/
|
|
192
|
+
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).
|
|
193
|
+
|
|
194
|
+
On self-host, a finalized run can also **gate a CI job**: `report.gate(fail_under=7, no_regression=True)` 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 an exit code - `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.
|
|
193
195
|
|
|
194
196
|
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.
|
|
195
197
|
|
|
@@ -311,7 +313,7 @@ evaluator = client.monitor.online_evaluators.builder(
|
|
|
311
313
|
client.monitor.online_evaluators.ratings(evaluator.id, window="7d")
|
|
312
314
|
```
|
|
313
315
|
|
|
314
|
-
An online evaluator can also judge **whole conversations** instead of single traces: pass `scope="session"` and the engine scores each multi-turn session once it's been idle for `idle_seconds`, re-scoring if the conversation resumes. And to close the loop with reality, `client.outcomes.report(...)`
|
|
316
|
+
An online evaluator can also judge **whole conversations** instead of single traces: pass `scope="session"` and the engine scores each multi-turn session once it's been idle for `idle_seconds`, re-scoring if the conversation resumes. And to close the loop with reality, two ground-truth streams feed the dashboard's Judge Calibration view (which measures how often AgentX's automated verdicts agree with what actually happened): `client.outcomes.report(...)` for after-the-fact system results (a reopened ticket, a human confirmation), and `client.feedback.report(...)` for end-user votes forwarded from your own app's UI - a "down" raises a "Negative user feedback" signal directly, no sampling or judge call involved. All self-host features.
|
|
315
317
|
|
|
316
318
|
```python
|
|
317
319
|
client.monitor.online_evaluators.builder(
|
|
@@ -328,6 +330,13 @@ client.outcomes.report(
|
|
|
328
330
|
is_negative=True,
|
|
329
331
|
reason="Customer reopened the ticket within 3 days",
|
|
330
332
|
)
|
|
333
|
+
|
|
334
|
+
client.feedback.report(
|
|
335
|
+
trace_id=trace_id,
|
|
336
|
+
rating="down", # "up" or "down"
|
|
337
|
+
comment="It never answered my question", # optional, the user's own words
|
|
338
|
+
end_user_id=current_user.id, # optional, opaque to AgentX
|
|
339
|
+
)
|
|
331
340
|
```
|
|
332
341
|
|
|
333
342
|
See **[TRACING.md](TRACING.md)** for the complete Monitor guide.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
VERSION = "0.6.16"
|
|
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
|