agentx-python 0.6.11__tar.gz → 0.6.12__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.11/agentx_python.egg-info → agentx_python-0.6.12}/PKG-INFO +15 -2
- {agentx_python-0.6.11 → agentx_python-0.6.12}/README.md +14 -1
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/client.py +2 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/models.py +1 -1
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/prompts.py +6 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/monitor/client.py +49 -1
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/monitor/models.py +59 -0
- agentx_python-0.6.12/agentx/monitor/online_evaluators.py +120 -0
- agentx_python-0.6.12/agentx/version.py +1 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12/agentx_python.egg-info}/PKG-INFO +15 -2
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx_python.egg-info/SOURCES.txt +1 -0
- agentx_python-0.6.11/agentx/version.py +0 -1
- {agentx_python-0.6.11 → agentx_python-0.6.12}/LICENSE +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/__init__.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/agentx.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/cli.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/__init__.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/_term.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/adapters/__init__.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/adapters/http_endpoint.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/adapters/precomputed.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/adapters/raw.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/datasets.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/evaluation_settings.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/redaction.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/reporting.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/results.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/runner.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/evaluations/tracing.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/exceptions.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/__init__.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/_perf.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/_traced_call.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/anthropic.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/autogen.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/crewai.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/google_adk.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/google_genai.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/langchain.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/litellm.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/llamaindex.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/openai.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/integrations/openai_agents.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/monitor/__init__.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/monitor/patterns.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/monitor/profile.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/monitor/signals.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/py.typed +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/resources/__init__.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/resources/agent.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/resources/conversation.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/resources/workforce.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/tracing/__init__.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/tracing/ci_types.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/tracing/ingest_client.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/tracing/tracer.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx/util.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx_python.egg-info/dependency_links.txt +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx_python.egg-info/entry_points.txt +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx_python.egg-info/not-zip-safe +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx_python.egg-info/requires.txt +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/agentx_python.egg-info/top_level.txt +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/setup.cfg +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/setup.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/tests/test_integration.py +0 -0
- {agentx_python-0.6.11 → agentx_python-0.6.12}/tests/test_integrations.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.12
|
|
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
|
|
@@ -298,6 +298,19 @@ Per-agent coverage/threshold settings (sample rate, retention, and threshold ove
|
|
|
298
298
|
client.monitor.profile.update("agent_123", threshold_overrides={"latencyMs": 15000})
|
|
299
299
|
```
|
|
300
300
|
|
|
301
|
+
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
|
+
|
|
303
|
+
```python
|
|
304
|
+
evaluator = client.monitor.online_evaluators.builder(
|
|
305
|
+
name="Helpfulness",
|
|
306
|
+
evaluation_settings_id=settings.id,
|
|
307
|
+
sample_rate=0.1,
|
|
308
|
+
alert_threshold=5,
|
|
309
|
+
).publish()
|
|
310
|
+
|
|
311
|
+
client.monitor.online_evaluators.ratings(evaluator.id, window="7d")
|
|
312
|
+
```
|
|
313
|
+
|
|
301
314
|
See **[TRACING.md](TRACING.md)** for the complete Monitor guide.
|
|
302
315
|
|
|
303
316
|
---
|
|
@@ -330,7 +343,7 @@ Ask a case's question several extra ways each run, LLM-paraphrased server-side,
|
|
|
330
343
|
Since AgentX doesn't own your agent's code, `client.evaluations.prompts` lets AgentX become your prompt's *source of truth* instead — the same problem LangSmith's Prompt Hub and Langfuse's Prompt Management solve. Pull a version at runtime, tag your eval runs (or live traces) with it, and let a judge propose a rewrite from your real worst-rated results — a human always has to approve before it publishes:
|
|
331
344
|
|
|
332
345
|
```python
|
|
333
|
-
prompt = client.evaluations.prompts.get("support-agent-system-prompt")
|
|
346
|
+
prompt = client.evaluations.prompts.get("support-agent-system-prompt") # or prompt.id
|
|
334
347
|
# use prompt.text as your own agent's system prompt
|
|
335
348
|
|
|
336
349
|
client.evaluations.run(
|
|
@@ -236,6 +236,19 @@ Per-agent coverage/threshold settings (sample rate, retention, and threshold ove
|
|
|
236
236
|
client.monitor.profile.update("agent_123", threshold_overrides={"latencyMs": 15000})
|
|
237
237
|
```
|
|
238
238
|
|
|
239
|
+
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`.
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
evaluator = client.monitor.online_evaluators.builder(
|
|
243
|
+
name="Helpfulness",
|
|
244
|
+
evaluation_settings_id=settings.id,
|
|
245
|
+
sample_rate=0.1,
|
|
246
|
+
alert_threshold=5,
|
|
247
|
+
).publish()
|
|
248
|
+
|
|
249
|
+
client.monitor.online_evaluators.ratings(evaluator.id, window="7d")
|
|
250
|
+
```
|
|
251
|
+
|
|
239
252
|
See **[TRACING.md](TRACING.md)** for the complete Monitor guide.
|
|
240
253
|
|
|
241
254
|
---
|
|
@@ -268,7 +281,7 @@ Ask a case's question several extra ways each run, LLM-paraphrased server-side,
|
|
|
268
281
|
Since AgentX doesn't own your agent's code, `client.evaluations.prompts` lets AgentX become your prompt's *source of truth* instead — the same problem LangSmith's Prompt Hub and Langfuse's Prompt Management solve. Pull a version at runtime, tag your eval runs (or live traces) with it, and let a judge propose a rewrite from your real worst-rated results — a human always has to approve before it publishes:
|
|
269
282
|
|
|
270
283
|
```python
|
|
271
|
-
prompt = client.evaluations.prompts.get("support-agent-system-prompt")
|
|
284
|
+
prompt = client.evaluations.prompts.get("support-agent-system-prompt") # or prompt.id
|
|
272
285
|
# use prompt.text as your own agent's system prompt
|
|
273
286
|
|
|
274
287
|
client.evaluations.run(
|
|
@@ -213,6 +213,8 @@ class EvaluationsClient:
|
|
|
213
213
|
return [Prompt(**p) for p in (data if isinstance(data, list) else data.get("prompts", []))]
|
|
214
214
|
|
|
215
215
|
def get_prompt(self, name: str, version: Optional[int] = None) -> Prompt:
|
|
216
|
+
# `name` doubles as an id: the backend route tries a name match first, then falls back to
|
|
217
|
+
# an id match (see engine's getPromptRowByNameOrId), so callers can pass either.
|
|
216
218
|
params = self._workspace_params() or {}
|
|
217
219
|
if version is not None:
|
|
218
220
|
params = {**params, "version": version}
|
|
@@ -132,7 +132,7 @@ class EvaluationSettings(BaseModel):
|
|
|
132
132
|
# Prompt registry — the external-agent analog to AgentX's native autotune. AgentX doesn't own
|
|
133
133
|
# your agent's code, so instead of branching/applying a config it becomes the prompt's source of
|
|
134
134
|
# truth (same shape as LangSmith's Prompt Hub / Langfuse's Prompt Management): pull a version at
|
|
135
|
-
# runtime with ``client.evaluations.prompts.get(
|
|
135
|
+
# runtime with ``client.evaluations.prompts.get(name_or_id)``, use ``prompt.text`` as your agent's
|
|
136
136
|
# system prompt, and tag your eval runs so the existing version-comparison view can tell you
|
|
137
137
|
# which published version scored higher — see ``client.evaluations.prompts`` docs.
|
|
138
138
|
# ---------------------------------------------------------------------------
|
|
@@ -34,6 +34,9 @@ class PromptClient:
|
|
|
34
34
|
}
|
|
35
35
|
),
|
|
36
36
|
)
|
|
37
|
+
|
|
38
|
+
``get()`` also accepts a prompt's ``id`` in place of its name, e.g.
|
|
39
|
+
``client.evaluations.prompts.get(prompt.id)``.
|
|
37
40
|
"""
|
|
38
41
|
|
|
39
42
|
def __init__(self, client: "EvaluationsClient"):
|
|
@@ -43,6 +46,9 @@ class PromptClient:
|
|
|
43
46
|
return self._client.create_prompt({"name": name, "text": text, "description": description})
|
|
44
47
|
|
|
45
48
|
def get(self, name: str, version: Optional[int] = None) -> Prompt:
|
|
49
|
+
"""Accepts either the prompt's name or its ``id`` (e.g. ``prompt.id`` from an earlier
|
|
50
|
+
``get``/``create`` call), useful for round-tripping an id you already have without a
|
|
51
|
+
second lookup method."""
|
|
46
52
|
return self._client.get_prompt(name, version=version)
|
|
47
53
|
|
|
48
54
|
def list(self) -> List[Prompt]:
|
|
@@ -7,7 +7,14 @@ from typing import Any, List, Optional
|
|
|
7
7
|
|
|
8
8
|
import requests
|
|
9
9
|
|
|
10
|
-
from agentx.monitor.models import
|
|
10
|
+
from agentx.monitor.models import (
|
|
11
|
+
MonitorPattern,
|
|
12
|
+
MonitorProfile,
|
|
13
|
+
MonitorSignal,
|
|
14
|
+
MonitorOnlineEvaluator,
|
|
15
|
+
OnlineEvaluatorRatingPoint,
|
|
16
|
+
OnlineEvaluatorEvent,
|
|
17
|
+
)
|
|
11
18
|
|
|
12
19
|
logger = logging.getLogger(__name__)
|
|
13
20
|
|
|
@@ -71,10 +78,12 @@ class MonitorClient:
|
|
|
71
78
|
from agentx.monitor.patterns import MonitorPatternClient
|
|
72
79
|
from agentx.monitor.signals import MonitorSignalClient
|
|
73
80
|
from agentx.monitor.profile import MonitorProfileClient
|
|
81
|
+
from agentx.monitor.online_evaluators import MonitorOnlineEvaluatorClient
|
|
74
82
|
|
|
75
83
|
self.patterns = MonitorPatternClient(self)
|
|
76
84
|
self.signals = MonitorSignalClient(self)
|
|
77
85
|
self.profile = MonitorProfileClient(self)
|
|
86
|
+
self.online_evaluators = MonitorOnlineEvaluatorClient(self)
|
|
78
87
|
|
|
79
88
|
# ------------------------------------------------------------------
|
|
80
89
|
# Low-level HTTP
|
|
@@ -137,6 +146,45 @@ class MonitorClient:
|
|
|
137
146
|
)
|
|
138
147
|
return MonitorPattern(**data["pattern"])
|
|
139
148
|
|
|
149
|
+
# ------------------------------------------------------------------
|
|
150
|
+
# Online evaluator endpoints
|
|
151
|
+
# ------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
def create_online_evaluator(self, payload: dict) -> MonitorOnlineEvaluator:
|
|
154
|
+
data = self._request("POST", "/online-evaluators", json=self._with_workspace(payload))
|
|
155
|
+
return MonitorOnlineEvaluator(**data["evaluator"])
|
|
156
|
+
|
|
157
|
+
def list_online_evaluators(self) -> List[MonitorOnlineEvaluator]:
|
|
158
|
+
data = self._request("GET", "/online-evaluators", params=self._workspace_params())
|
|
159
|
+
return [MonitorOnlineEvaluator(**e) for e in data.get("evaluators", [])]
|
|
160
|
+
|
|
161
|
+
def get_online_evaluator(self, evaluator_id: str) -> MonitorOnlineEvaluator:
|
|
162
|
+
data = self._request(
|
|
163
|
+
"GET", f"/online-evaluators/{evaluator_id}", params=self._workspace_params()
|
|
164
|
+
)
|
|
165
|
+
return MonitorOnlineEvaluator(**data["evaluator"])
|
|
166
|
+
|
|
167
|
+
def update_online_evaluator(self, evaluator_id: str, payload: dict) -> MonitorOnlineEvaluator:
|
|
168
|
+
data = self._request(
|
|
169
|
+
"PUT", f"/online-evaluators/{evaluator_id}", json=self._with_workspace(payload)
|
|
170
|
+
)
|
|
171
|
+
return MonitorOnlineEvaluator(**data["evaluator"])
|
|
172
|
+
|
|
173
|
+
def delete_online_evaluator(self, evaluator_id: str) -> None:
|
|
174
|
+
self._request(
|
|
175
|
+
"DELETE", f"/online-evaluators/{evaluator_id}", params=self._workspace_params()
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def get_online_evaluator_ratings(self, evaluator_id: str, window: str) -> List[OnlineEvaluatorRatingPoint]:
|
|
179
|
+
params = {**(self._workspace_params() or {}), "window": window}
|
|
180
|
+
data = self._request("GET", f"/online-evaluators/{evaluator_id}/ratings", params=params)
|
|
181
|
+
return [OnlineEvaluatorRatingPoint(**p) for p in data.get("points", [])]
|
|
182
|
+
|
|
183
|
+
def get_online_evaluator_events(self, evaluator_id: str, window: str) -> List[OnlineEvaluatorEvent]:
|
|
184
|
+
params = {**(self._workspace_params() or {}), "window": window}
|
|
185
|
+
data = self._request("GET", f"/online-evaluators/{evaluator_id}/events", params=params)
|
|
186
|
+
return [OnlineEvaluatorEvent(**e) for e in data.get("events", [])]
|
|
187
|
+
|
|
140
188
|
# ------------------------------------------------------------------
|
|
141
189
|
# Signal endpoints
|
|
142
190
|
# ------------------------------------------------------------------
|
|
@@ -37,6 +37,65 @@ class MonitorPattern(BaseModel):
|
|
|
37
37
|
extra = "ignore"
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
class MonitorOnlineEvaluator(BaseModel):
|
|
41
|
+
"""Continuous LLM-judge scoring of a sample of live production traffic, distinct from a
|
|
42
|
+
MonitorPattern (which matches rules, not judgment). Built via
|
|
43
|
+
``client.monitor.online_evaluators.builder(...).publish()``. References an
|
|
44
|
+
``evaluation_settings_id`` (an Evaluator config: criteria, judge prompt, judge model) rather
|
|
45
|
+
than storing its own copy, the same config datasets/Evaluate runs use.
|
|
46
|
+
|
|
47
|
+
A score below ``alert_threshold`` raises/updates a Signal (``client.monitor.signals``), the
|
|
48
|
+
same triage surface a failing MonitorPattern already lands on, tagged with ``severity``. Set
|
|
49
|
+
``alert_threshold=None`` to score without ever raising a Signal.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
id: str = Field(alias="_id")
|
|
53
|
+
name: str
|
|
54
|
+
evaluation_settings_id: str = Field(alias="evaluationSettingsId")
|
|
55
|
+
sample_rate: float = Field(default=0.1, alias="sampleRate")
|
|
56
|
+
scope_mode: str = Field(default="all", alias="scopeMode")
|
|
57
|
+
agent_ids: List[str] = Field(default_factory=list, alias="agentIds")
|
|
58
|
+
enabled: bool = True
|
|
59
|
+
alert_threshold: Optional[float] = Field(default=5, alias="alertThreshold")
|
|
60
|
+
severity: str = "medium"
|
|
61
|
+
created_at: Optional[str] = Field(default=None, alias="createdAt")
|
|
62
|
+
|
|
63
|
+
class Config:
|
|
64
|
+
populate_by_name = True
|
|
65
|
+
extra = "ignore"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class OnlineEvaluatorRatingPoint(BaseModel):
|
|
69
|
+
"""One bucket of a ratings-over-time series, see
|
|
70
|
+
``client.monitor.online_evaluators.ratings(evaluator_id)``."""
|
|
71
|
+
|
|
72
|
+
label: str
|
|
73
|
+
ts: int
|
|
74
|
+
average_rating: Optional[float] = Field(default=None, alias="averageRating")
|
|
75
|
+
count: int = 0
|
|
76
|
+
|
|
77
|
+
class Config:
|
|
78
|
+
populate_by_name = True
|
|
79
|
+
extra = "ignore"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class OnlineEvaluatorEvent(BaseModel):
|
|
83
|
+
"""One individually scored trace behind a point on the ratings series, worst-rated first,
|
|
84
|
+
see ``client.monitor.online_evaluators.events(evaluator_id)``."""
|
|
85
|
+
|
|
86
|
+
id: str
|
|
87
|
+
trace_id: str = Field(alias="traceId")
|
|
88
|
+
rating: float
|
|
89
|
+
justification: Optional[str] = None
|
|
90
|
+
created_at: str = Field(alias="createdAt")
|
|
91
|
+
input: str
|
|
92
|
+
output: str
|
|
93
|
+
|
|
94
|
+
class Config:
|
|
95
|
+
populate_by_name = True
|
|
96
|
+
extra = "ignore"
|
|
97
|
+
|
|
98
|
+
|
|
40
99
|
class SignalOccurrence(BaseModel):
|
|
41
100
|
"""One hit behind a signal, capped at the server's most recent N per signal."""
|
|
42
101
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Dict, List, Optional, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from agentx.monitor.models import MonitorOnlineEvaluator, OnlineEvaluatorRatingPoint, OnlineEvaluatorEvent
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from agentx.monitor.client import MonitorClient
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MonitorOnlineEvaluatorBuilder:
|
|
15
|
+
"""Fluent builder for creating an online evaluator: continuous LLM-judge scoring of a
|
|
16
|
+
sample of live production traffic, distinct from a MonitorPattern's rule matching.
|
|
17
|
+
``evaluation_settings_id`` must reference an existing Evaluator config (criteria, judge
|
|
18
|
+
prompt, judge model), the same config datasets/Evaluate runs use, see
|
|
19
|
+
``client.evaluations.settings.builder(...)``.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
client: "MonitorClient",
|
|
25
|
+
name: str,
|
|
26
|
+
evaluation_settings_id: str,
|
|
27
|
+
sample_rate: float = 0.1,
|
|
28
|
+
scope_mode: str = "all",
|
|
29
|
+
agent_ids: Optional[List[str]] = None,
|
|
30
|
+
enabled: bool = True,
|
|
31
|
+
alert_threshold: Optional[float] = 5,
|
|
32
|
+
severity: str = "medium",
|
|
33
|
+
):
|
|
34
|
+
self._client = client
|
|
35
|
+
self._payload: Dict[str, Any] = {
|
|
36
|
+
"name": name,
|
|
37
|
+
"evaluationSettingsId": evaluation_settings_id,
|
|
38
|
+
# Every check here is a real LLM call against your own API key: keep this low
|
|
39
|
+
# unless you want to score every trace.
|
|
40
|
+
"sampleRate": sample_rate,
|
|
41
|
+
"scopeMode": scope_mode,
|
|
42
|
+
"agentIds": agent_ids or [],
|
|
43
|
+
"enabled": enabled,
|
|
44
|
+
# A score below this raises/updates a Signal, same triage surface a failing
|
|
45
|
+
# MonitorPattern already lands on. None scores without ever raising one.
|
|
46
|
+
"alertThreshold": alert_threshold,
|
|
47
|
+
"severity": severity,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
def publish(self) -> MonitorOnlineEvaluator:
|
|
51
|
+
logger.info("Publishing online evaluator '%s'", self._payload["name"])
|
|
52
|
+
return self._client.create_online_evaluator(self._payload)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class MonitorOnlineEvaluatorClient:
|
|
56
|
+
"""Thin wrapper surfaced as ``client.monitor.online_evaluators``."""
|
|
57
|
+
|
|
58
|
+
def __init__(self, client: "MonitorClient"):
|
|
59
|
+
self._client = client
|
|
60
|
+
|
|
61
|
+
def builder(
|
|
62
|
+
self,
|
|
63
|
+
name: str,
|
|
64
|
+
evaluation_settings_id: str,
|
|
65
|
+
sample_rate: float = 0.1,
|
|
66
|
+
scope_mode: str = "all",
|
|
67
|
+
agent_ids: Optional[List[str]] = None,
|
|
68
|
+
enabled: bool = True,
|
|
69
|
+
alert_threshold: Optional[float] = 5,
|
|
70
|
+
severity: str = "medium",
|
|
71
|
+
) -> MonitorOnlineEvaluatorBuilder:
|
|
72
|
+
return MonitorOnlineEvaluatorBuilder(
|
|
73
|
+
self._client,
|
|
74
|
+
name=name,
|
|
75
|
+
evaluation_settings_id=evaluation_settings_id,
|
|
76
|
+
sample_rate=sample_rate,
|
|
77
|
+
scope_mode=scope_mode,
|
|
78
|
+
agent_ids=agent_ids,
|
|
79
|
+
enabled=enabled,
|
|
80
|
+
alert_threshold=alert_threshold,
|
|
81
|
+
severity=severity,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def get(self, evaluator_id: str) -> MonitorOnlineEvaluator:
|
|
85
|
+
return self._client.get_online_evaluator(evaluator_id)
|
|
86
|
+
|
|
87
|
+
def list(self) -> List[MonitorOnlineEvaluator]:
|
|
88
|
+
return self._client.list_online_evaluators()
|
|
89
|
+
|
|
90
|
+
def update(self, evaluator_id: str, **fields: Any) -> MonitorOnlineEvaluator:
|
|
91
|
+
"""Partial update: pass only the fields you want to change, e.g.
|
|
92
|
+
``client.monitor.online_evaluators.update(id, enabled=False)`` to pause one, or
|
|
93
|
+
``sample_rate=0.25`` to change its sampling. Field names match the builder's
|
|
94
|
+
(``evaluation_settings_id``, ``sample_rate``, ``scope_mode``, ``agent_ids``, ``enabled``,
|
|
95
|
+
``alert_threshold``, ``severity``). Pass ``alert_threshold=None`` to stop this evaluator
|
|
96
|
+
from ever raising a Signal.
|
|
97
|
+
"""
|
|
98
|
+
alias_map = {
|
|
99
|
+
"evaluation_settings_id": "evaluationSettingsId",
|
|
100
|
+
"sample_rate": "sampleRate",
|
|
101
|
+
"scope_mode": "scopeMode",
|
|
102
|
+
"agent_ids": "agentIds",
|
|
103
|
+
"alert_threshold": "alertThreshold",
|
|
104
|
+
}
|
|
105
|
+
payload = {alias_map.get(key, key): value for key, value in fields.items()}
|
|
106
|
+
return self._client.update_online_evaluator(evaluator_id, payload)
|
|
107
|
+
|
|
108
|
+
def delete(self, evaluator_id: str) -> None:
|
|
109
|
+
self._client.delete_online_evaluator(evaluator_id)
|
|
110
|
+
|
|
111
|
+
def ratings(self, evaluator_id: str, window: str = "7d") -> List[OnlineEvaluatorRatingPoint]:
|
|
112
|
+
"""Bucketed average-rating-over-time for this evaluator. ``window`` is one of
|
|
113
|
+
``"24h"``, ``"7d"``, ``"30d"``."""
|
|
114
|
+
return self._client.get_online_evaluator_ratings(evaluator_id, window)
|
|
115
|
+
|
|
116
|
+
def events(self, evaluator_id: str, window: str = "7d") -> List[OnlineEvaluatorEvent]:
|
|
117
|
+
"""Individually scored traces behind the ratings series, worst-rated first and capped
|
|
118
|
+
(see the dashboard's Online Evaluators tab for the same view), lets a low point on the
|
|
119
|
+
ratings series be traced back to exactly which conversation(s) caused it and why."""
|
|
120
|
+
return self._client.get_online_evaluator_events(evaluator_id, window)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION = "0.6.12"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentx-python
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.12
|
|
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
|
|
@@ -298,6 +298,19 @@ Per-agent coverage/threshold settings (sample rate, retention, and threshold ove
|
|
|
298
298
|
client.monitor.profile.update("agent_123", threshold_overrides={"latencyMs": 15000})
|
|
299
299
|
```
|
|
300
300
|
|
|
301
|
+
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
|
+
|
|
303
|
+
```python
|
|
304
|
+
evaluator = client.monitor.online_evaluators.builder(
|
|
305
|
+
name="Helpfulness",
|
|
306
|
+
evaluation_settings_id=settings.id,
|
|
307
|
+
sample_rate=0.1,
|
|
308
|
+
alert_threshold=5,
|
|
309
|
+
).publish()
|
|
310
|
+
|
|
311
|
+
client.monitor.online_evaluators.ratings(evaluator.id, window="7d")
|
|
312
|
+
```
|
|
313
|
+
|
|
301
314
|
See **[TRACING.md](TRACING.md)** for the complete Monitor guide.
|
|
302
315
|
|
|
303
316
|
---
|
|
@@ -330,7 +343,7 @@ Ask a case's question several extra ways each run, LLM-paraphrased server-side,
|
|
|
330
343
|
Since AgentX doesn't own your agent's code, `client.evaluations.prompts` lets AgentX become your prompt's *source of truth* instead — the same problem LangSmith's Prompt Hub and Langfuse's Prompt Management solve. Pull a version at runtime, tag your eval runs (or live traces) with it, and let a judge propose a rewrite from your real worst-rated results — a human always has to approve before it publishes:
|
|
331
344
|
|
|
332
345
|
```python
|
|
333
|
-
prompt = client.evaluations.prompts.get("support-agent-system-prompt")
|
|
346
|
+
prompt = client.evaluations.prompts.get("support-agent-system-prompt") # or prompt.id
|
|
334
347
|
# use prompt.text as your own agent's system prompt
|
|
335
348
|
|
|
336
349
|
client.evaluations.run(
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
VERSION = "0.6.11"
|
|
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
|