evalrun 0.4.0__py3-none-any.whl

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 (100) hide show
  1. agents/__init__.py +6 -0
  2. agents/auditor/__init__.py +13 -0
  3. agents/auditor/budget_auditor.py +91 -0
  4. agents/auditor/parser.py +139 -0
  5. agents/auditor/prompts.py +64 -0
  6. agents/auditor/schema.py +67 -0
  7. agents/base.py +20 -0
  8. agents/reflection/__init__.py +3 -0
  9. agents/reflection/agent.py +77 -0
  10. agents/reflection/prompts.py +18 -0
  11. agents/research/__init__.py +4 -0
  12. agents/research/agent.py +45 -0
  13. agents/research/planner.py +52 -0
  14. agents/research/prompts.py +14 -0
  15. agents/support/__init__.py +5 -0
  16. agents/support/triage_agent.py +45 -0
  17. agents/travel/__init__.py +11 -0
  18. agents/travel/agent.py +377 -0
  19. agents/travel/prompts.py +30 -0
  20. agents/travel/session.py +110 -0
  21. cli/__init__.py +6 -0
  22. cli/demo.py +47 -0
  23. cli/formatter.py +93 -0
  24. cli/html_reporter.py +647 -0
  25. cli/main.py +423 -0
  26. cli/progress.py +38 -0
  27. cli/resolver.py +99 -0
  28. evalrun-0.4.0.dist-info/METADATA +268 -0
  29. evalrun-0.4.0.dist-info/RECORD +100 -0
  30. evalrun-0.4.0.dist-info/WHEEL +5 -0
  31. evalrun-0.4.0.dist-info/entry_points.txt +2 -0
  32. evalrun-0.4.0.dist-info/licenses/LICENSE +0 -0
  33. evalrun-0.4.0.dist-info/top_level.txt +4 -0
  34. framework/__init__.py +70 -0
  35. framework/core/__init__.py +17 -0
  36. framework/core/adapters.py +118 -0
  37. framework/core/contracts.py +88 -0
  38. framework/core/suite.py +44 -0
  39. framework/evaluation/__init__.py +22 -0
  40. framework/evaluation/base.py +29 -0
  41. framework/evaluation/dimensions.py +7 -0
  42. framework/evaluation/engine.py +110 -0
  43. framework/evaluation/evaluators/__init__.py +7 -0
  44. framework/evaluation/evaluators/adaptability.py +27 -0
  45. framework/evaluation/evaluators/base_llm.py +104 -0
  46. framework/evaluation/evaluators/constraint.py +27 -0
  47. framework/evaluation/evaluators/information_accuracy.py +41 -0
  48. framework/evaluation/evaluators/personalization.py +27 -0
  49. framework/evaluation/evaluators/planning.py +27 -0
  50. framework/evaluation/evaluators/support.py +81 -0
  51. framework/evaluation/prompts/__init__.py +11 -0
  52. framework/evaluation/prompts/adaptability.py +57 -0
  53. framework/evaluation/prompts/base.py +52 -0
  54. framework/evaluation/prompts/constraint.py +41 -0
  55. framework/evaluation/prompts/information_accuracy.py +79 -0
  56. framework/evaluation/prompts/personalization.py +57 -0
  57. framework/evaluation/prompts/planning.py +61 -0
  58. framework/evaluation/runner.py +363 -0
  59. framework/evaluation/testing.py +25 -0
  60. framework/exceptions.py +49 -0
  61. framework/llms/__init__.py +8 -0
  62. framework/llms/base.py +37 -0
  63. framework/llms/factory.py +38 -0
  64. framework/llms/gemini.py +85 -0
  65. framework/llms/mock.py +25 -0
  66. framework/llms/openai.py +94 -0
  67. framework/llms/openai_compatible.py +139 -0
  68. framework/mcp/__init__.py +20 -0
  69. framework/mcp/client.py +62 -0
  70. framework/mcp/constraints.py +125 -0
  71. framework/mcp/revision_summary.py +122 -0
  72. framework/mcp/server.py +49 -0
  73. framework/memory/__init__.py +3 -0
  74. framework/memory/base.py +17 -0
  75. framework/models.py +83 -0
  76. framework/parser.py +45 -0
  77. framework/parsers/__init__.py +12 -0
  78. framework/parsers/frontmatter.py +28 -0
  79. framework/parsers/mapper.py +66 -0
  80. framework/parsers/markdown.py +122 -0
  81. framework/parsers/transformers.py +112 -0
  82. framework/profiles/__init__.py +28 -0
  83. framework/profiles/registry.py +104 -0
  84. framework/profiles/support.py +27 -0
  85. framework/profiles/travel.py +78 -0
  86. framework/regression/__init__.py +17 -0
  87. framework/regression/comparator.py +273 -0
  88. framework/regression/loader.py +145 -0
  89. framework/sdk.py +151 -0
  90. framework/utils.py +41 -0
  91. framework/verification/__init__.py +13 -0
  92. framework/verification/base.py +32 -0
  93. framework/verification/extractor.py +105 -0
  94. framework/verification/local.py +122 -0
  95. framework/verification/models.py +112 -0
  96. framework/verification/pipeline.py +36 -0
  97. framework/verification/prompts.py +24 -0
  98. framework/verification/utils.py +54 -0
  99. ui/__init__.py +1 -0
  100. ui/server.py +255 -0
cli/formatter.py ADDED
@@ -0,0 +1,93 @@
1
+ """Terminal report formatter and credential redaction utilities for evalrun CLI."""
2
+
3
+ from typing import Any, Dict, List, Optional
4
+ from framework.models import EvaluationResult
5
+
6
+ SECRET_KEYS = {"api_key", "apikey", "authorization", "password", "secret", "bearer", "token"}
7
+
8
+
9
+ def redact_credentials(data: Any) -> Any:
10
+ """Recursively redacts sensitive credentials from dictionaries or lists for manifest persistence."""
11
+ if isinstance(data, dict):
12
+ redacted = {}
13
+ for key, val in data.items():
14
+ if key.lower() in SECRET_KEYS:
15
+ redacted[key] = "[REDACTED]"
16
+ else:
17
+ redacted[key] = redact_credentials(val)
18
+ return redacted
19
+ elif isinstance(data, list):
20
+ return [redact_credentials(item) for item in data]
21
+ return data
22
+
23
+
24
+ def format_terminal_summary(
25
+ results: List[EvaluationResult],
26
+ manifest: Dict[str, Any],
27
+ regression_report: Optional[Dict[str, Any]] = None,
28
+ ) -> str:
29
+ """Renders a clean ASCII summary table for terminal display."""
30
+ lines = []
31
+ lines.append("=" * 85)
32
+ lines.append(" EVALRUN BENCHMARK SUMMARY")
33
+ lines.append("=" * 85)
34
+ lines.append(f" Run ID: {manifest.get('run_id', 'N/A')}")
35
+ lines.append(f" Target Model: {manifest.get('target_model', {}).get('model_name', 'N/A')} ({manifest.get('target_model', {}).get('base_url', 'N/A')})")
36
+ lines.append(f" Judge Model: {manifest.get('judge_model', {}).get('model_name', 'N/A')}")
37
+ if manifest.get("baseline_path"):
38
+ lines.append(f" Baseline: {manifest.get('baseline_path')}")
39
+ lines.append(f" Total Runs: {len(results)}")
40
+ lines.append("-" * 85)
41
+
42
+ if regression_report:
43
+ lines.append(f"{'Scenario Name':<28} | {'Score':<7} | {'Delta':<8} | {'Evaluator':<10} | {'Auditor':<8} | {'Status':<10}")
44
+ else:
45
+ lines.append(f"{'Scenario Name':<32} | {'Score':<8} | {'Evaluator':<10} | {'Auditor Gate':<12}")
46
+ lines.append("-" * 85)
47
+
48
+ all_passed = True
49
+ reg_scenarios_by_id = {}
50
+ if regression_report:
51
+ if regression_report.get("release_blocked"):
52
+ all_passed = False
53
+ for s in regression_report.get("scenarios", []):
54
+ reg_scenarios_by_id[s["scenario_id"]] = s
55
+
56
+ for res in results:
57
+ eval_status = "PASS" if res.passed else "FAIL"
58
+ if not res.passed:
59
+ all_passed = False
60
+
61
+ audit_status = "N/A"
62
+ if hasattr(res, "agent_metadata") and isinstance(res.agent_metadata, dict):
63
+ gate = res.agent_metadata.get("audit_gate_decision")
64
+ if gate:
65
+ audit_status = "PASS" if gate == "PASS" else "BLOCK"
66
+ if gate != "PASS":
67
+ all_passed = False
68
+
69
+ if regression_report:
70
+ reg_info = reg_scenarios_by_id.get(res.benchmark_id, {})
71
+ delta_val = reg_info.get("overall_delta")
72
+ delta_str = f"{delta_val:+.2f}" if delta_val is not None else "N/A"
73
+ status_str = reg_info.get("status", "OK")
74
+ lines.append(
75
+ f"{res.benchmark_name[:28]:<28} | {res.overall_score:6.2f} | {delta_str:<8} | {eval_status:<10} | {audit_status:<8} | {status_str:<10}"
76
+ )
77
+ else:
78
+ lines.append(f"{res.benchmark_name[:32]:<32} | {res.overall_score:6.2f} | {eval_status:<10} | {audit_status:<12}")
79
+
80
+ lines.append("=" * 85)
81
+ if regression_report and regression_report.get("regression_detected"):
82
+ final_verdict = "RELEASE BLOCKED: REGRESSION OR GATE FAILURE (Exit Code: 1)"
83
+ elif not all_passed:
84
+ final_verdict = "EVALUATION OR GATE FAILURE (Exit Code: 1)"
85
+ else:
86
+ final_verdict = "ALL SCENARIOS PASSED (Exit Code: 0)"
87
+
88
+ lines.append(f" Final Verdict: {final_verdict}")
89
+ lines.append("=" * 85)
90
+ lines.append(f" Artifacts saved to: {manifest.get('output_dir', './eval_results')}")
91
+ lines.append("")
92
+
93
+ return "\n".join(lines)