agentx-python 0.6.6__tar.gz → 0.6.7__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.
Files changed (54) hide show
  1. {agentx_python-0.6.6 → agentx_python-0.6.7}/PKG-INFO +6 -1
  2. {agentx_python-0.6.6 → agentx_python-0.6.7}/README.md +5 -0
  3. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/_term.py +6 -0
  4. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/client.py +23 -2
  5. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/models.py +63 -5
  6. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/runner.py +70 -4
  7. agentx_python-0.6.7/agentx/version.py +1 -0
  8. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx_python.egg-info/PKG-INFO +6 -1
  9. agentx_python-0.6.6/agentx/version.py +0 -1
  10. {agentx_python-0.6.6 → agentx_python-0.6.7}/LICENSE +0 -0
  11. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/__init__.py +0 -0
  12. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/agentx.py +0 -0
  13. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/__init__.py +0 -0
  14. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/adapters/__init__.py +0 -0
  15. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/adapters/http_endpoint.py +0 -0
  16. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/adapters/precomputed.py +0 -0
  17. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/adapters/raw.py +0 -0
  18. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/datasets.py +0 -0
  19. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/evaluation_settings.py +0 -0
  20. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/redaction.py +0 -0
  21. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/reporting.py +0 -0
  22. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/results.py +0 -0
  23. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/evaluations/tracing.py +0 -0
  24. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/exceptions.py +0 -0
  25. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/integrations/__init__.py +0 -0
  26. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/integrations/_perf.py +0 -0
  27. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/integrations/anthropic.py +0 -0
  28. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/integrations/crewai.py +0 -0
  29. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/integrations/google_adk.py +0 -0
  30. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/integrations/google_genai.py +0 -0
  31. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/integrations/langchain.py +0 -0
  32. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/integrations/openai_agents.py +0 -0
  33. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/monitor/__init__.py +0 -0
  34. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/monitor/client.py +0 -0
  35. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/monitor/models.py +0 -0
  36. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/monitor/patterns.py +0 -0
  37. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/py.typed +0 -0
  38. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/resources/__init__.py +0 -0
  39. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/resources/agent.py +0 -0
  40. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/resources/conversation.py +0 -0
  41. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/resources/workforce.py +0 -0
  42. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/tracing/__init__.py +0 -0
  43. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/tracing/ci_types.py +0 -0
  44. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/tracing/ingest_client.py +0 -0
  45. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/tracing/tracer.py +0 -0
  46. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx/util.py +0 -0
  47. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx_python.egg-info/SOURCES.txt +0 -0
  48. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx_python.egg-info/dependency_links.txt +0 -0
  49. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx_python.egg-info/not-zip-safe +0 -0
  50. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx_python.egg-info/requires.txt +0 -0
  51. {agentx_python-0.6.6 → agentx_python-0.6.7}/agentx_python.egg-info/top_level.txt +0 -0
  52. {agentx_python-0.6.6 → agentx_python-0.6.7}/setup.cfg +0 -0
  53. {agentx_python-0.6.6 → agentx_python-0.6.7}/setup.py +0 -0
  54. {agentx_python-0.6.6 → agentx_python-0.6.7}/tests/test_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentx-python
3
- Version: 0.6.6
3
+ Version: 0.6.7
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
@@ -286,8 +286,13 @@ report = (
286
286
  print(report.average_rating) # LLM-graded score, 0–10
287
287
  print(report.cosine_similarity) # embedding cosine, 0–1 (None if not enabled)
288
288
  print(report.jaccard_similarity) # token-set overlap, 0–1 (None if not enabled)
289
+
290
+ print(report.summary) # AI-generated narrative from .analyze()
291
+ print(report.recommendations) # list of prioritized, actionable fixes
289
292
  ```
290
293
 
294
+ `.analyze()` also generates a full qualitative report (strengths, weaknesses, instruction adherence, reasoning quality, and recommendations), running the same durable, multi-judge pipeline as the dashboard's "Analyze" button. `analyze(mode=..., quality_mode=..., judges=[...])` controls how items are scored and by which models. See [AI analysis report](EVALUATIONS.md#ai-analysis-report) in the full guide for the complete field and parameter reference.
295
+
291
296
  See **[EVALUATIONS.md](EVALUATIONS.md)** for the full guide — dataset builder, framework adapters, similarity metrics, and the complete API reference.
292
297
 
293
298
  ---
@@ -238,8 +238,13 @@ report = (
238
238
  print(report.average_rating) # LLM-graded score, 0–10
239
239
  print(report.cosine_similarity) # embedding cosine, 0–1 (None if not enabled)
240
240
  print(report.jaccard_similarity) # token-set overlap, 0–1 (None if not enabled)
241
+
242
+ print(report.summary) # AI-generated narrative from .analyze()
243
+ print(report.recommendations) # list of prioritized, actionable fixes
241
244
  ```
242
245
 
246
+ `.analyze()` also generates a full qualitative report (strengths, weaknesses, instruction adherence, reasoning quality, and recommendations), running the same durable, multi-judge pipeline as the dashboard's "Analyze" button. `analyze(mode=..., quality_mode=..., judges=[...])` controls how items are scored and by which models. See [AI analysis report](EVALUATIONS.md#ai-analysis-report) in the full guide for the complete field and parameter reference.
247
+
243
248
  See **[EVALUATIONS.md](EVALUATIONS.md)** for the full guide — dataset builder, framework adapters, similarity metrics, and the complete API reference.
244
249
 
245
250
  ---
@@ -71,6 +71,12 @@ class Spinner:
71
71
  self._thread.start()
72
72
  return self
73
73
 
74
+ def update(self, message: str) -> None:
75
+ """Change the displayed message while the spinner keeps running."""
76
+ self._message = message
77
+ if not _IS_TTY:
78
+ print(f" {message}...", flush=True)
79
+
74
80
  def __exit__(self, *_) -> None:
75
81
  if not _IS_TTY:
76
82
  return
@@ -9,6 +9,7 @@ from typing import Any, Dict, List, Optional
9
9
  import requests
10
10
 
11
11
  from agentx.evaluations.models import (
12
+ AnalysisStatus,
12
13
  BatchAppendResponse,
13
14
  Dataset,
14
15
  EvaluationResult,
@@ -238,8 +239,28 @@ class EvaluationsClient:
238
239
  "POST", f"/runs/{run_id}/finalize", json={"status": "completed"}
239
240
  )
240
241
 
241
- def analyze_run(self, run_id: str) -> Dict[str, Any]:
242
- return self._request("POST", f"/runs/{run_id}/analyze", json={}, timeout=300)
242
+ def analyze_run(
243
+ self,
244
+ run_id: str,
245
+ mode: Optional[str] = None,
246
+ quality_mode: Optional[str] = None,
247
+ judges: Optional[List[str]] = None,
248
+ ) -> Dict[str, Any]:
249
+ # Starts the durable analysis job and returns immediately (e.g. {"jobId": ..., "status":
250
+ # "pending"}); poll get_analysis_status() until it reaches a terminal status, then call
251
+ # get_report(). mode/quality_mode/judges mirror the dashboard's AnalyzeEvaluationRequest.
252
+ payload: Dict[str, Any] = {}
253
+ if mode is not None:
254
+ payload["mode"] = mode
255
+ if quality_mode is not None:
256
+ payload["qualityMode"] = quality_mode
257
+ if judges is not None:
258
+ payload["judges"] = [{"model": m} for m in judges]
259
+ return self._request("POST", f"/runs/{run_id}/analyze", json=payload, timeout=30)
260
+
261
+ def get_analysis_status(self, run_id: str) -> AnalysisStatus:
262
+ data = self._request("GET", f"/runs/{run_id}/analyze-status")
263
+ return AnalysisStatus(**data)
243
264
 
244
265
  def get_run(self, run_id: str) -> Dict[str, Any]:
245
266
  return self._request("GET", f"/runs/{run_id}")
@@ -438,11 +438,9 @@ class SovereigntyIndex(BaseModel):
438
438
  extra = "ignore"
439
439
 
440
440
 
441
- class Report(BaseModel):
442
- run_id: str = Field(alias="runId")
443
- dataset_id: str = Field(alias="datasetId")
444
- status: str = "completed"
445
- statistics: Optional[ReportStatistics] = None
441
+ class AnalysisResult(BaseModel):
442
+ """Shared qualitative-report fields, produced by ``client.evaluations.run(...).analyze()``."""
443
+
446
444
  summary: Optional[str] = None
447
445
  consistency_score: Optional[float] = Field(default=None, alias="consistencyScore")
448
446
  instruction_adherence: Optional[ReportInstructionAdherence] = Field(
@@ -461,6 +459,17 @@ class Report(BaseModel):
461
459
  weaknesses: List[str] = Field(default_factory=list)
462
460
  overall_rating: Optional[str] = Field(default=None, alias="overallRating")
463
461
  recommendations: List[ReportRecommendation] = Field(default_factory=list)
462
+
463
+ class Config:
464
+ populate_by_name = True
465
+ extra = "ignore"
466
+
467
+
468
+ class Report(AnalysisResult):
469
+ run_id: str = Field(alias="runId")
470
+ dataset_id: str = Field(alias="datasetId")
471
+ status: str = "completed"
472
+ statistics: Optional[ReportStatistics] = None
464
473
  low_scoring_cases: List[Dict[str, Any]] = Field(
465
474
  default_factory=list, alias="lowScoringCases"
466
475
  )
@@ -548,3 +557,52 @@ class Report(BaseModel):
548
557
  def average_rating(self) -> Optional[float]:
549
558
  """Convenience accessor matching cosine_similarity / jaccard_similarity."""
550
559
  return self.statistics.average_rating if self.statistics is not None else None
560
+
561
+
562
+ class AnalysisLevelProgress(BaseModel):
563
+ total: int = 0
564
+ completed: int = 0
565
+ failed: int = 0
566
+ percentage: int = 0
567
+
568
+ class Config:
569
+ extra = "ignore"
570
+
571
+
572
+ class AnalysisProgress(BaseModel):
573
+ overall_percentage: int = Field(default=0, alias="overallPercentage")
574
+ current_level: Optional[str] = Field(default=None, alias="currentLevel")
575
+ levels: Dict[str, AnalysisLevelProgress] = Field(default_factory=dict)
576
+
577
+ class Config:
578
+ populate_by_name = True
579
+ extra = "ignore"
580
+
581
+
582
+ class AnalysisFailureReason(BaseModel):
583
+ code: str
584
+ message: str
585
+ retryable: bool = False
586
+
587
+ class Config:
588
+ extra = "ignore"
589
+
590
+
591
+ class AnalysisStatus(BaseModel):
592
+ """Returned by ``client.evaluations.run(...).analyze()``'s polling loop
593
+ (``EvaluationsClient.get_analysis_status``). ``status`` is terminal once it's one of
594
+ "completed", "partially_failed", or "failed"."""
595
+
596
+ job_id: Optional[str] = Field(default=None, alias="jobId")
597
+ status: str = "not_started"
598
+ progress: AnalysisProgress = Field(default_factory=AnalysisProgress)
599
+ failure_reason: Optional[AnalysisFailureReason] = Field(default=None, alias="failureReason")
600
+ warnings: List[Dict[str, Any]] = Field(default_factory=list)
601
+
602
+ class Config:
603
+ populate_by_name = True
604
+ extra = "ignore"
605
+
606
+ @property
607
+ def is_terminal(self) -> bool:
608
+ return self.status in ("completed", "partially_failed", "failed")
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ import time
4
5
  import uuid
5
6
  from typing import Any, Callable, Dict, List, Optional, Set, Union
6
7
 
@@ -9,6 +10,7 @@ from agentx.evaluations.adapters.precomputed import PrecomputedAdapter
9
10
  from agentx.evaluations.adapters.http_endpoint import HttpEndpointAdapter
10
11
  from agentx.evaluations.client import EvaluationsClient
11
12
  from agentx.evaluations.models import (
13
+ AnalysisStatus,
12
14
  Dataset,
13
15
  EvaluationCase,
14
16
  EvaluationResult,
@@ -43,6 +45,15 @@ AdapterLike = Union[
43
45
  HttpEndpointAdapter,
44
46
  ]
45
47
 
48
+ _ANALYSIS_LEVEL_LABELS = {
49
+ "l1_score": "scoring responses",
50
+ "l2_question_reduce": "reducing questions",
51
+ "l3_cluster_reduce": "reducing clusters",
52
+ "l4_final_reduce": "writing final report",
53
+ }
54
+
55
+ _DEFAULT_JUDGE_MODEL = "gpt-5.5"
56
+
46
57
 
47
58
  class EvaluationRunContext:
48
59
  """
@@ -228,12 +239,61 @@ class EvaluationRunContext:
228
239
  # Step 3: analyze + report
229
240
  # ------------------------------------------------------------------
230
241
 
231
- def analyze(self) -> Report:
242
+ def analyze(
243
+ self,
244
+ mode: Optional[str] = None,
245
+ quality_mode: Optional[str] = None,
246
+ judges: Optional[List[str]] = None,
247
+ poll_interval: float = 5.0,
248
+ timeout: float = 1800.0,
249
+ ) -> Report:
250
+ """Generate the qualitative AI analysis report.
251
+
252
+ Runs the same durable, multi-stage pipeline as the dashboard's "Analyze" button: each
253
+ response is scored by 1-3 LLM judges (``judges``), then reduced into the final report.
254
+ This starts the job and polls until it finishes, which can take noticeably longer than a
255
+ single LLM call for larger runs.
256
+
257
+ Args:
258
+ mode: "auto" (default), "sync", or "batch" - how item scoring executes server-side.
259
+ quality_mode: "quality_first" or "balanced" - how many items get a second/third judge.
260
+ judges: 1-3 model ids, e.g. ``["gpt-5.5", "claude-opus-4-8"]``. Defaults to a single
261
+ judge, ``["gpt-5.5"]``, rather than the dashboard's 3-judge default - SDK runs are
262
+ typically lighter-weight, quick-start evaluations.
263
+ poll_interval: seconds between status checks while waiting.
264
+ timeout: give up waiting after this many seconds (the job keeps running server-side;
265
+ call ``get_report()`` later to check on it).
266
+ """
267
+ if judges is not None and not (1 <= len(judges) <= 3):
268
+ raise ValueError("judges must contain 1-3 model ids")
269
+ resolved_judges = judges if judges is not None else [_DEFAULT_JUDGE_MODEL]
270
+
232
271
  print()
233
- with Spinner("Analyzing — AI is reviewing your results"):
272
+ with Spinner("Analyzing — AI is reviewing your results") as spinner:
234
273
  try:
235
- self._client.analyze_run(self._run.run_id)
236
- print(f" {green('✓')} Analysis complete")
274
+ self._client.analyze_run(
275
+ self._run.run_id,
276
+ mode=mode,
277
+ quality_mode=quality_mode,
278
+ judges=resolved_judges,
279
+ )
280
+ deadline = time.monotonic() + timeout
281
+ status = self._client.get_analysis_status(self._run.run_id)
282
+ while not status.is_terminal and time.monotonic() < deadline:
283
+ level = _ANALYSIS_LEVEL_LABELS.get(status.progress.current_level, "")
284
+ spinner.update(
285
+ f"Analyzing, {level + ' ' if level else ''}{status.progress.overall_percentage}%"
286
+ )
287
+ time.sleep(poll_interval)
288
+ status = self._client.get_analysis_status(self._run.run_id)
289
+
290
+ if not status.is_terminal:
291
+ print(f" {yellow('!')} Still running after {int(timeout)}s, check the dashboard for status")
292
+ elif status.status == "failed":
293
+ reason = status.failure_reason.message if status.failure_reason else "unknown error"
294
+ print(f" {red('✗')} Analyze failed: {dim(reason)}")
295
+ else:
296
+ print(f" {green('✓')} Analysis complete")
237
297
  except Exception as exc:
238
298
  print(f" {red('✗')} Analyze failed: {dim(str(exc))}")
239
299
  logger.warning("Analyze request failed: %s", exc)
@@ -280,6 +340,12 @@ class EvaluationsRunner:
280
340
  against."""
281
341
  return self._client.list_models(provider)
282
342
 
343
+ def get_analysis_status(self, run_id: str) -> AnalysisStatus:
344
+ """Check on an in-progress ``.analyze()`` job by run id, without needing
345
+ the ``EvaluationRunContext`` that started it (e.g. from a separate
346
+ script execution)."""
347
+ return self._client.get_analysis_status(run_id)
348
+
283
349
  def run(
284
350
  self,
285
351
  dataset_id: str,
@@ -0,0 +1 @@
1
+ VERSION = "0.6.7"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentx-python
3
- Version: 0.6.6
3
+ Version: 0.6.7
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
@@ -286,8 +286,13 @@ report = (
286
286
  print(report.average_rating) # LLM-graded score, 0–10
287
287
  print(report.cosine_similarity) # embedding cosine, 0–1 (None if not enabled)
288
288
  print(report.jaccard_similarity) # token-set overlap, 0–1 (None if not enabled)
289
+
290
+ print(report.summary) # AI-generated narrative from .analyze()
291
+ print(report.recommendations) # list of prioritized, actionable fixes
289
292
  ```
290
293
 
294
+ `.analyze()` also generates a full qualitative report (strengths, weaknesses, instruction adherence, reasoning quality, and recommendations), running the same durable, multi-judge pipeline as the dashboard's "Analyze" button. `analyze(mode=..., quality_mode=..., judges=[...])` controls how items are scored and by which models. See [AI analysis report](EVALUATIONS.md#ai-analysis-report) in the full guide for the complete field and parameter reference.
295
+
291
296
  See **[EVALUATIONS.md](EVALUATIONS.md)** for the full guide — dataset builder, framework adapters, similarity metrics, and the complete API reference.
292
297
 
293
298
  ---
@@ -1 +0,0 @@
1
- VERSION = "0.6.6"
File without changes
File without changes
File without changes