openagent-eval 0.1.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 (120) hide show
  1. openagent_eval/__init__.py +4 -0
  2. openagent_eval/cli/__init__.py +5 -0
  3. openagent_eval/cli/commands/__init__.py +17 -0
  4. openagent_eval/cli/commands/compare.py +75 -0
  5. openagent_eval/cli/commands/doctor.py +100 -0
  6. openagent_eval/cli/commands/init.py +51 -0
  7. openagent_eval/cli/commands/list_evaluations.py +49 -0
  8. openagent_eval/cli/commands/report.py +64 -0
  9. openagent_eval/cli/commands/run.py +77 -0
  10. openagent_eval/cli/main.py +43 -0
  11. openagent_eval/cli/utils/__init__.py +6 -0
  12. openagent_eval/cli/utils/callbacks.py +14 -0
  13. openagent_eval/cli/utils/constants.py +47 -0
  14. openagent_eval/cli/utils/display.py +88 -0
  15. openagent_eval/cli/utils/helpers.py +118 -0
  16. openagent_eval/config/__init__.py +21 -0
  17. openagent_eval/config/loader.py +121 -0
  18. openagent_eval/config/models.py +142 -0
  19. openagent_eval/config/validator.py +87 -0
  20. openagent_eval/core/__init__.py +8 -0
  21. openagent_eval/core/engine.py +154 -0
  22. openagent_eval/core/executor.py +163 -0
  23. openagent_eval/core/pipeline.py +312 -0
  24. openagent_eval/core/registry.py +152 -0
  25. openagent_eval/datasets/__init__.py +37 -0
  26. openagent_eval/datasets/base.py +190 -0
  27. openagent_eval/datasets/csv_loader.py +178 -0
  28. openagent_eval/datasets/factory.py +115 -0
  29. openagent_eval/datasets/hf_loader.py +283 -0
  30. openagent_eval/datasets/json_loader.py +156 -0
  31. openagent_eval/datasets/jsonl_loader.py +165 -0
  32. openagent_eval/datasets/models.py +88 -0
  33. openagent_eval/datasets/pdf_loader.py +250 -0
  34. openagent_eval/exceptions/__init__.py +50 -0
  35. openagent_eval/exceptions/base.py +33 -0
  36. openagent_eval/exceptions/cli.py +97 -0
  37. openagent_eval/exceptions/config.py +41 -0
  38. openagent_eval/exceptions/dataset.py +119 -0
  39. openagent_eval/exceptions/metric.py +123 -0
  40. openagent_eval/exceptions/plugin.py +93 -0
  41. openagent_eval/exceptions/provider.py +123 -0
  42. openagent_eval/integrations/__init__.py +0 -0
  43. openagent_eval/metrics/__init__.py +113 -0
  44. openagent_eval/metrics/base.py +85 -0
  45. openagent_eval/metrics/cost/__init__.py +11 -0
  46. openagent_eval/metrics/cost/tokens.py +114 -0
  47. openagent_eval/metrics/generation/__init__.py +27 -0
  48. openagent_eval/metrics/generation/bertscore.py +117 -0
  49. openagent_eval/metrics/generation/bleu.py +100 -0
  50. openagent_eval/metrics/generation/exact_match.py +51 -0
  51. openagent_eval/metrics/generation/f1.py +77 -0
  52. openagent_eval/metrics/generation/faithfulness.py +118 -0
  53. openagent_eval/metrics/generation/hallucination.py +119 -0
  54. openagent_eval/metrics/generation/relevancy.py +128 -0
  55. openagent_eval/metrics/generation/rouge.py +86 -0
  56. openagent_eval/metrics/generation/similarity.py +102 -0
  57. openagent_eval/metrics/models.py +63 -0
  58. openagent_eval/metrics/performance/__init__.py +11 -0
  59. openagent_eval/metrics/performance/latency.py +64 -0
  60. openagent_eval/metrics/retrieval/__init__.py +23 -0
  61. openagent_eval/metrics/retrieval/hit_rate.py +59 -0
  62. openagent_eval/metrics/retrieval/mrr.py +66 -0
  63. openagent_eval/metrics/retrieval/ndcg.py +125 -0
  64. openagent_eval/metrics/retrieval/precision.py +64 -0
  65. openagent_eval/metrics/retrieval/precision_at_k.py +62 -0
  66. openagent_eval/metrics/retrieval/recall.py +65 -0
  67. openagent_eval/metrics/retrieval/recall_at_k.py +67 -0
  68. openagent_eval/plugins/__init__.py +22 -0
  69. openagent_eval/plugins/discovery.py +107 -0
  70. openagent_eval/plugins/examples/__init__.py +9 -0
  71. openagent_eval/plugins/examples/custom_metric.py +70 -0
  72. openagent_eval/plugins/loader.py +130 -0
  73. openagent_eval/plugins/manager.py +125 -0
  74. openagent_eval/providers/__init__.py +18 -0
  75. openagent_eval/providers/base/__init__.py +11 -0
  76. openagent_eval/providers/base/llm.py +96 -0
  77. openagent_eval/providers/base/retriever.py +83 -0
  78. openagent_eval/providers/embedders/__init__.py +37 -0
  79. openagent_eval/providers/embedders/base.py +58 -0
  80. openagent_eval/providers/embedders/mock.py +44 -0
  81. openagent_eval/providers/embedders/sentence_transformers.py +69 -0
  82. openagent_eval/providers/factory.py +176 -0
  83. openagent_eval/providers/llm/__init__.py +50 -0
  84. openagent_eval/providers/llm/anthropic.py +253 -0
  85. openagent_eval/providers/llm/gemini.py +232 -0
  86. openagent_eval/providers/llm/groq.py +314 -0
  87. openagent_eval/providers/llm/mock.py +93 -0
  88. openagent_eval/providers/llm/ollama.py +406 -0
  89. openagent_eval/providers/llm/openai.py +330 -0
  90. openagent_eval/providers/llm/openrouter.py +224 -0
  91. openagent_eval/providers/models.py +112 -0
  92. openagent_eval/providers/retrievers/__init__.py +67 -0
  93. openagent_eval/providers/retrievers/_scoring.py +91 -0
  94. openagent_eval/providers/retrievers/bm25.py +145 -0
  95. openagent_eval/providers/retrievers/chroma.py +186 -0
  96. openagent_eval/providers/retrievers/elasticsearch.py +132 -0
  97. openagent_eval/providers/retrievers/faiss.py +140 -0
  98. openagent_eval/providers/retrievers/http.py +189 -0
  99. openagent_eval/providers/retrievers/memory.py +174 -0
  100. openagent_eval/providers/retrievers/mock.py +69 -0
  101. openagent_eval/providers/retrievers/pgvector.py +130 -0
  102. openagent_eval/providers/retrievers/pinecone.py +101 -0
  103. openagent_eval/providers/retrievers/qdrant.py +104 -0
  104. openagent_eval/providers/retrievers/weaviate.py +101 -0
  105. openagent_eval/reports/__init__.py +33 -0
  106. openagent_eval/reports/base.py +164 -0
  107. openagent_eval/reports/comparison.py +167 -0
  108. openagent_eval/reports/html.py +158 -0
  109. openagent_eval/reports/json_report.py +150 -0
  110. openagent_eval/reports/manager.py +200 -0
  111. openagent_eval/reports/markdown.py +185 -0
  112. openagent_eval/reports/templates/report.html +259 -0
  113. openagent_eval/reports/terminal.py +203 -0
  114. openagent_eval/types/__init__.py +0 -0
  115. openagent_eval/utils/__init__.py +0 -0
  116. openagent_eval-0.1.0.dist-info/METADATA +356 -0
  117. openagent_eval-0.1.0.dist-info/RECORD +120 -0
  118. openagent_eval-0.1.0.dist-info/WHEEL +4 -0
  119. openagent_eval-0.1.0.dist-info/entry_points.txt +2 -0
  120. openagent_eval-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,4 @@
1
+ """OpenAgent Eval - Open-source CLI framework for evaluating RAG systems and AI Agents."""
2
+
3
+ __version__ = "0.1.0"
4
+ __author__ = "OpenAgent Eval Contributors"
@@ -0,0 +1,5 @@
1
+ """CLI module for OpenAgent Eval."""
2
+
3
+ from openagent_eval.cli.main import app
4
+
5
+ __all__ = ["app"]
@@ -0,0 +1,17 @@
1
+ """CLI commands for OpenAgent Eval."""
2
+
3
+ from openagent_eval.cli.commands.init import init_command
4
+ from openagent_eval.cli.commands.run import run_command
5
+ from openagent_eval.cli.commands.report import report_command
6
+ from openagent_eval.cli.commands.compare import compare_command
7
+ from openagent_eval.cli.commands.list_evaluations import list_command
8
+ from openagent_eval.cli.commands.doctor import doctor_command
9
+
10
+ __all__ = [
11
+ "init_command",
12
+ "run_command",
13
+ "report_command",
14
+ "compare_command",
15
+ "list_command",
16
+ "doctor_command",
17
+ ]
@@ -0,0 +1,75 @@
1
+ """Compare command for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+
10
+ from openagent_eval.exceptions.cli import CommandError
11
+ from openagent_eval.reports.comparison import ComparisonReport
12
+ from openagent_eval.reports.base import ExperimentComparison
13
+ from openagent_eval.reports.manager import ReportManager
14
+ from openagent_eval.cli.utils.constants import DEFAULT_OUTPUT_DIR
15
+ from openagent_eval.cli.utils.helpers import resolve_report_id
16
+
17
+ console = Console()
18
+
19
+
20
+ def compare_command(
21
+ experiment_a: str = typer.Argument(
22
+ help="First experiment ID or path.",
23
+ ),
24
+ experiment_b: str = typer.Argument(
25
+ help="Second experiment ID or path.",
26
+ ),
27
+ metrics: list[str] = typer.Option(
28
+ None,
29
+ "--metrics",
30
+ "-m",
31
+ help="Specific metrics to compare (default: all).",
32
+ ),
33
+ output_dir: str = typer.Option(
34
+ None,
35
+ "--output-dir",
36
+ "-d",
37
+ help="Directory where reports are stored (default: ./reports).",
38
+ ),
39
+ ) -> None:
40
+ """Compare two evaluation experiments side by side."""
41
+ console.print("[bold blue]OpenAgent Eval[/bold blue] - Experiment Comparison")
42
+ console.print(f"[dim]Comparing: {experiment_a} vs {experiment_b}[/dim]\n")
43
+
44
+ manager = ReportManager()
45
+ reports_dir = Path(output_dir) if output_dir else DEFAULT_OUTPUT_DIR
46
+
47
+ try:
48
+ data_a = resolve_report_id(experiment_a, reports_dir, manager)
49
+ except CommandError as e:
50
+ console.print(f"[red]Error:[/red] {e.message}")
51
+ raise typer.Exit(code=e.exit_code) from None
52
+
53
+ try:
54
+ data_b = resolve_report_id(experiment_b, reports_dir, manager)
55
+ except CommandError as e:
56
+ console.print(f"[red]Error:[/red] {e.message}")
57
+ raise typer.Exit(code=e.exit_code) from None
58
+
59
+ # Reconstruct EvaluationReports and extract PipelineResults
60
+ report_a = manager.reconstruct(data_a)
61
+ report_b = manager.reconstruct(data_b)
62
+
63
+ # Create ExperimentComparison (needs PipelineResult objects)
64
+ comparison = ExperimentComparison(
65
+ baseline_name=experiment_a,
66
+ experiment_name=experiment_b,
67
+ baseline_results=report_a.result,
68
+ experiment_results=report_b.result,
69
+ )
70
+
71
+ # Generate comparison
72
+ generator = ComparisonReport()
73
+ comparison_output = generator.generate(comparison)
74
+
75
+ console.print(comparison_output)
@@ -0,0 +1,100 @@
1
+ """Doctor command for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib
6
+ import os
7
+ import sys
8
+
9
+ import typer
10
+ from rich.console import Console
11
+ from rich.table import Table
12
+
13
+ from openagent_eval import __version__
14
+
15
+ console = Console()
16
+
17
+
18
+ def doctor_command(
19
+ verbose: bool = typer.Option(
20
+ False,
21
+ "--verbose",
22
+ "-v",
23
+ help="Show detailed information.",
24
+ ),
25
+ ) -> None:
26
+ """Check environment and dependencies for OpenAgent Eval."""
27
+ console.print("[bold blue]OpenAgent Eval[/bold blue] - Environment Check\n")
28
+
29
+ table = Table(title="Environment Status")
30
+ table.add_column("Component", style="cyan")
31
+ table.add_column("Status", style="bold")
32
+ table.add_column("Details", style="dim")
33
+
34
+ python_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
35
+ python_ok = sys.version_info >= (3, 11)
36
+ table.add_row(
37
+ "Python",
38
+ "[green]OK[/green]" if python_ok else "[red]MISSING[/red]",
39
+ f"v{python_version}" + ("" if python_ok else " (3.11+ required)"),
40
+ )
41
+
42
+ dependencies = [
43
+ ("typer", "CLI framework"),
44
+ ("rich", "Terminal UI"),
45
+ ("pydantic", "Data validation"),
46
+ ("yaml", "Configuration"),
47
+ ("loguru", "Logging"),
48
+ ("jinja2", "HTML templates"),
49
+ ]
50
+
51
+ for dep_name, dep_desc in dependencies:
52
+ try:
53
+ importlib.import_module(dep_name.replace("-", "_"))
54
+ table.add_row(dep_name, "[green]OK[/green]", dep_desc)
55
+ except ImportError:
56
+ table.add_row(dep_name, "[red]MISSING[/red]", f"{dep_desc} (not installed)")
57
+
58
+ console.print(table)
59
+
60
+ key_table = Table(title="API Key Availability")
61
+ key_table.add_column("Provider", style="cyan")
62
+ key_table.add_column("Environment Variable", style="yellow")
63
+ key_table.add_column("Status", style="bold")
64
+
65
+ api_keys = [
66
+ ("OpenAI", "OPENAI_API_KEY"),
67
+ ("Gemini", "GEMINI_API_KEY"),
68
+ ("Anthropic", "ANTHROPIC_API_KEY"),
69
+ ("Groq", "GROQ_API_KEY"),
70
+ ]
71
+
72
+ available_providers: list[str] = []
73
+ for provider_name, env_var in api_keys:
74
+ key_value = os.environ.get(env_var)
75
+ if key_value:
76
+ key_table.add_row(provider_name, env_var, "[green]Available[/green]")
77
+ available_providers.append(provider_name)
78
+ else:
79
+ key_table.add_row(provider_name, env_var, "[dim]Not set[/dim]")
80
+
81
+ console.print(key_table)
82
+
83
+ console.print("\n[bold]Summary:[/bold]")
84
+ if python_ok:
85
+ console.print("[green]OK[/green] Python version is compatible")
86
+ else:
87
+ console.print("[red]MISSING[/red] Python 3.11+ required")
88
+
89
+ if available_providers:
90
+ console.print(
91
+ f"[green]OK[/green] Available providers: {', '.join(available_providers)}"
92
+ )
93
+ else:
94
+ console.print("[yellow]WARNING[/yellow] No API keys configured")
95
+
96
+ if verbose:
97
+ console.print(f"\n[dim]Python: {sys.executable}[/dim]")
98
+ console.print(f"[dim]Version: {__version__}[/dim]")
99
+
100
+ console.print("\n[dim]Run 'pip install openagent-eval[all]' to install all dependencies.[/dim]")
@@ -0,0 +1,51 @@
1
+ """Init command for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+ from rich.prompt import Confirm
10
+
11
+ from openagent_eval.exceptions import ConfigurationError
12
+ from openagent_eval.cli.utils.constants import DEFAULT_CONFIG_CONTENT
13
+
14
+ console = Console()
15
+
16
+
17
+ def init_command(
18
+ config_path: str = typer.Option(
19
+ "config.yaml",
20
+ "--config",
21
+ "-c",
22
+ help="Path to create configuration file.",
23
+ ),
24
+ force: bool = typer.Option(
25
+ False,
26
+ "--force",
27
+ "-f",
28
+ help="Overwrite existing configuration file.",
29
+ ),
30
+ ) -> None:
31
+ """Create a new evaluation configuration file."""
32
+ path = Path(config_path)
33
+
34
+ if path.exists() and not force and not Confirm.ask(
35
+ f"Configuration file '{config_path}' already exists. Overwrite?"
36
+ ):
37
+ console.print("[yellow]Aborted.[/yellow]")
38
+ raise typer.Exit()
39
+
40
+ try:
41
+ path.parent.mkdir(parents=True, exist_ok=True)
42
+ path.write_text(DEFAULT_CONFIG_CONTENT, encoding="utf-8")
43
+ console.print(f"[green]OK[/green] Configuration created: {config_path}")
44
+ console.print("\n[yellow]Next steps:[/yellow]")
45
+ console.print(" 1. Edit the configuration file")
46
+ console.print(" 2. Run [bold]oaeval run[/bold] to start evaluation")
47
+ except OSError as e:
48
+ raise ConfigurationError(
49
+ message=f"Failed to create configuration: {e}",
50
+ config_path=config_path,
51
+ ) from e
@@ -0,0 +1,49 @@
1
+ """List command for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+
10
+ from openagent_eval.reports.manager import ReportManager
11
+ from openagent_eval.cli.utils.constants import DEFAULT_OUTPUT_DIR
12
+ from openagent_eval.cli.utils.display import display_report_list
13
+
14
+ console = Console()
15
+
16
+
17
+ def list_command(
18
+ limit: int = typer.Option(
19
+ 10,
20
+ "--limit",
21
+ "-l",
22
+ help="Number of evaluations to show.",
23
+ ),
24
+ output: str = typer.Option(
25
+ None,
26
+ "--output",
27
+ "-o",
28
+ help="Filter by output format.",
29
+ ),
30
+ output_dir: str = typer.Option(
31
+ None,
32
+ "--output-dir",
33
+ "-d",
34
+ help="Directory where reports are stored (default: ./reports).",
35
+ ),
36
+ ) -> None:
37
+ """List previous evaluation runs."""
38
+ console.print("[bold blue]OpenAgent Eval[/bold blue] - Evaluation History\n")
39
+
40
+ manager = ReportManager()
41
+ reports_dir = Path(output_dir) if output_dir else DEFAULT_OUTPUT_DIR
42
+
43
+ try:
44
+ reports = manager.list_reports(reports_dir)
45
+ except Exception as e:
46
+ console.print(f"[red]Error:[/red] Failed to list reports: {e}")
47
+ raise typer.Exit(code=1) from e
48
+
49
+ display_report_list(reports, limit, output, reports_dir, manager)
@@ -0,0 +1,64 @@
1
+ """Report command for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+
10
+ from openagent_eval.exceptions.cli import CommandError
11
+ from openagent_eval.reports.manager import ReportManager
12
+ from openagent_eval.reports.terminal import TerminalReport
13
+ from openagent_eval.cli.utils.constants import DEFAULT_OUTPUT_DIR
14
+ from openagent_eval.cli.utils.helpers import get_report_generator, resolve_report_id
15
+
16
+ console = Console()
17
+
18
+
19
+ def report_command(
20
+ report_id: str = typer.Argument(
21
+ help="Report ID or 'latest' for the most recent report.",
22
+ ),
23
+ output: str = typer.Option(
24
+ "terminal",
25
+ "--output",
26
+ "-o",
27
+ help="Output format (terminal, markdown, html, json).",
28
+ ),
29
+ output_dir: str = typer.Option(
30
+ None,
31
+ "--output-dir",
32
+ "-d",
33
+ help="Directory where reports are stored (default: ./reports).",
34
+ ),
35
+ ) -> None:
36
+ """View evaluation reports."""
37
+ console.print("[bold blue]OpenAgent Eval[/bold blue] - Report Viewer")
38
+ console.print(f"[dim]Report: {report_id}[/dim]\n")
39
+
40
+ manager = ReportManager()
41
+ reports_dir = Path(output_dir) if output_dir else DEFAULT_OUTPUT_DIR
42
+
43
+ try:
44
+ data = resolve_report_id(report_id, reports_dir, manager)
45
+ except CommandError as e:
46
+ console.print(f"[red]Error:[/red] {e.message}")
47
+ raise typer.Exit(code=e.exit_code) from None
48
+
49
+ evaluation_report = manager.reconstruct(data)
50
+
51
+ try:
52
+ generator = get_report_generator(output)
53
+ except CommandError as e:
54
+ console.print(f"[red]Error:[/red] {e.message}")
55
+ raise typer.Exit(code=e.exit_code) from None
56
+
57
+ if output == "terminal":
58
+ gen = TerminalReport()
59
+ gen.print_report(evaluation_report)
60
+ else:
61
+ report_content = generator.generate(evaluation_report)
62
+ console.print(report_content)
63
+
64
+ console.print(f"\n[dim]Report ID: {data.get('report_id', 'unknown')}[/dim]")
@@ -0,0 +1,77 @@
1
+ """Run command for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import typer
8
+ from rich.console import Console
9
+ from rich.progress import Progress, SpinnerColumn, TextColumn
10
+
11
+ from openagent_eval import __version__
12
+ from openagent_eval.exceptions import ConfigurationError
13
+ from openagent_eval.reports.manager import ReportManager
14
+ from openagent_eval.cli.utils.helpers import (
15
+ apply_output_override,
16
+ execute_evaluation,
17
+ load_config_from_path,
18
+ load_dataset_for_run,
19
+ )
20
+ from openagent_eval.cli.utils.display import display_run_result
21
+
22
+ console = Console()
23
+
24
+
25
+ def run_command(
26
+ config_path: str = typer.Argument(
27
+ help="Path to configuration file.",
28
+ ),
29
+ output: str = typer.Option(
30
+ None,
31
+ "--output",
32
+ "-o",
33
+ help="Override output format (terminal, markdown, html, json).",
34
+ ),
35
+ verbose: bool = typer.Option(
36
+ False,
37
+ "--verbose",
38
+ "-v",
39
+ help="Enable verbose output.",
40
+ ),
41
+ ) -> None:
42
+ """Run evaluation pipeline with the specified configuration."""
43
+ path = Path(config_path)
44
+
45
+ if not path.exists():
46
+ raise ConfigurationError(
47
+ message=f"Configuration file not found: {config_path}",
48
+ config_path=config_path,
49
+ )
50
+
51
+ console.print(f"[bold blue]OpenAgent Eval[/bold blue] v{__version__}")
52
+ console.print(f"[dim]Configuration: {config_path}[/dim]\n")
53
+
54
+ with Progress(
55
+ SpinnerColumn(),
56
+ TextColumn("[progress.description]{task.description}"),
57
+ console=console,
58
+ ) as progress:
59
+ task = progress.add_task("Loading configuration...", total=None)
60
+ config = load_config_from_path(config_path)
61
+ apply_output_override(config, output)
62
+
63
+ progress.update(task, description="Loading dataset...")
64
+ dataset_items = load_dataset_for_run(config)
65
+
66
+ progress.update(task, description="Running evaluation...")
67
+ report = execute_evaluation(config, dataset_items)
68
+
69
+ progress.update(task, description="Generating report...")
70
+ format_name = config.report.output.value
71
+ manager = ReportManager()
72
+ output_dir = Path(config.report.output_dir)
73
+ report_path = manager.save_report(report, output_dir)
74
+
75
+ progress.update(task, description="Complete!", completed=True)
76
+
77
+ display_run_result(report, format_name, report_path, output_dir, verbose)
@@ -0,0 +1,43 @@
1
+ """Main CLI entry point for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+
7
+ from openagent_eval.cli.utils.callbacks import version_callback
8
+ from openagent_eval.cli.commands.init import init_command
9
+ from openagent_eval.cli.commands.run import run_command
10
+ from openagent_eval.cli.commands.report import report_command
11
+ from openagent_eval.cli.commands.compare import compare_command
12
+ from openagent_eval.cli.commands.list_evaluations import list_command
13
+ from openagent_eval.cli.commands.doctor import doctor_command
14
+
15
+ app = typer.Typer(
16
+ name="oaeval",
17
+ help="Open-source CLI framework for evaluating RAG systems and AI Agents.",
18
+ no_args_is_help=True,
19
+ add_completion=False,
20
+ )
21
+
22
+
23
+ @app.callback()
24
+ def main(
25
+ version: bool = typer.Option(
26
+ False,
27
+ "--version",
28
+ "-V",
29
+ help="Show version and exit.",
30
+ callback=version_callback,
31
+ is_eager=True,
32
+ ),
33
+ ) -> None:
34
+ """OpenAgent Eval - Evaluate RAG systems and AI Agents."""
35
+
36
+
37
+ # Register commands with explicit names
38
+ app.command(name="init")(init_command)
39
+ app.command(name="run")(run_command)
40
+ app.command(name="report")(report_command)
41
+ app.command(name="compare")(compare_command)
42
+ app.command(name="list")(list_command)
43
+ app.command(name="doctor")(doctor_command)
@@ -0,0 +1,6 @@
1
+ """CLI utility helpers for OpenAgent Eval."""
2
+
3
+ from openagent_eval.cli.utils.callbacks import version_callback
4
+ from openagent_eval.cli.utils.constants import DEFAULT_CONFIG_CONTENT
5
+
6
+ __all__ = ["version_callback", "DEFAULT_CONFIG_CONTENT"]
@@ -0,0 +1,14 @@
1
+ """CLI callbacks for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+
7
+
8
+ def version_callback(value: bool) -> None:
9
+ """Print version and exit."""
10
+ if value:
11
+ from openagent_eval import __version__
12
+
13
+ typer.echo(f"OpenAgent Eval v{__version__}")
14
+ raise typer.Exit()
@@ -0,0 +1,47 @@
1
+ """CLI constants for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ DEFAULT_OUTPUT_DIR = Path("./reports")
8
+
9
+ DEFAULT_CONFIG_CONTENT = """\
10
+ # OpenAgent Eval Configuration
11
+ # See documentation for options: https://github.com/OpenAgentHQ/openagent-eval
12
+ #
13
+ # For a fully offline dry-run (no API keys / vector store required), set:
14
+ # llm.provider: mock
15
+ # retriever.provider: mock
16
+
17
+ dataset:
18
+ path: data/questions.json
19
+ # limit: 100
20
+
21
+ llm:
22
+ provider: openai
23
+ model: gpt-4o-mini
24
+ temperature: 0.0
25
+
26
+ retriever:
27
+ provider: chroma
28
+ settings:
29
+ collection_name: my_collection
30
+
31
+ metrics:
32
+ retrieval:
33
+ - context_precision
34
+ - context_recall
35
+ - mrr
36
+ generation:
37
+ - faithfulness
38
+ - answer_relevancy
39
+ performance:
40
+ - latency
41
+ cost:
42
+ - token_count
43
+
44
+ report:
45
+ output: terminal
46
+ output_dir: ./reports
47
+ """
@@ -0,0 +1,88 @@
1
+ """CLI display helpers for OpenAgent Eval."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+
11
+ console = Console()
12
+
13
+
14
+ def display_run_result(
15
+ report: Any,
16
+ format_name: str,
17
+ report_path: Path,
18
+ output_dir: Path,
19
+ verbose: bool,
20
+ ) -> None:
21
+ """Display the evaluation run result."""
22
+ console.print("\n[green]OK[/green] Evaluation complete!")
23
+
24
+ if hasattr(report, "summary"):
25
+ summary = report.summary
26
+ total = summary.get("total_items", summary.get("total", 0))
27
+ errors = summary.get("failed_evaluations", summary.get("errors", 0))
28
+ console.print(f"[dim]Items: {total} | Errors: {errors}[/dim]")
29
+
30
+ console.print(f"[dim]Report saved to: {report_path}[/dim]")
31
+
32
+
33
+ def display_report_list(
34
+ reports: list[dict[str, str]],
35
+ limit: int,
36
+ output_filter: str | None,
37
+ output_dir: Path,
38
+ manager: Any,
39
+ ) -> None:
40
+ """Display a table of evaluation reports."""
41
+ from openagent_eval.reports.manager import ReportManager
42
+
43
+ if not reports:
44
+ console.print("[yellow]No evaluations found.[/yellow]")
45
+ return
46
+
47
+ if output_filter:
48
+ filtered: list[dict[str, str]] = []
49
+ for r in reports:
50
+ try:
51
+ data = manager.load_report(r["report_id"], output_dir)
52
+ report_format = (
53
+ data.get("config", {}).get("report", {}).get("output", "terminal")
54
+ )
55
+ if report_format == output_filter:
56
+ filtered.append(r)
57
+ except (FileNotFoundError, KeyError):
58
+ continue
59
+ reports = filtered
60
+
61
+ reports = reports[:limit]
62
+
63
+ table = Table(title="Recent Evaluations")
64
+ table.add_column("ID", style="cyan")
65
+ table.add_column("Date", style="green")
66
+ table.add_column("Config", style="yellow")
67
+ table.add_column("Status", style="bold")
68
+
69
+ for r in reports:
70
+ report_id = r["report_id"]
71
+ created_at = r.get("created_at", "unknown")
72
+ config_name = "unknown"
73
+ status = "OK"
74
+ try:
75
+ data = manager.load_report(report_id, output_dir)
76
+ config_name = data.get("config", {}).get("dataset", {}).get("path", "unknown")
77
+ errors = data.get("errors", [])
78
+ status = "[green]OK[/green]" if not errors else "[red]FAILED[/red]"
79
+ except (FileNotFoundError, KeyError):
80
+ status = "[yellow]UNKNOWN[/yellow]"
81
+
82
+ if created_at and "T" in created_at:
83
+ created_at = created_at.split("T")[0]
84
+
85
+ table.add_row(report_id, created_at, config_name, status)
86
+
87
+ console.print(table)
88
+ console.print(f"\n[dim]Showing {len(reports)} evaluations[/dim]")