agnes-the-ai-analyst/cli/commands/admin_metrics.py

89 lines
2.9 KiB
Python

"""`agnes admin metrics {import,export,validate}` — lifted from cli/commands/metrics.py.
Write paths to metric definitions live under `admin` because they mutate the
server-side metric registry (DuckDB direct, no API). Read paths (list/show)
live in `agnes catalog --metrics`.
"""
from pathlib import Path
import typer
admin_metrics_app = typer.Typer(help="Admin: metric definition management")
@admin_metrics_app.command("import")
def import_metrics(
path: str = typer.Argument(..., help="Path to a YAML file or directory of YAML files"),
):
"""Import metric definitions from YAML into DuckDB (direct, no API)."""
from src.db import get_system_db
from src.repositories.metrics import MetricRepository
import_path = Path(path)
if not import_path.exists():
typer.echo(f"Path not found: {path}", err=True)
raise typer.Exit(1)
conn = get_system_db()
try:
repo = MetricRepository(conn)
count = repo.import_from_yaml(import_path)
typer.echo(f"Imported {count} metric(s) from {path}")
finally:
conn.close()
@admin_metrics_app.command("export")
def export_metrics(
output_dir: str = typer.Option("./export/", "--dir", help="Output directory for YAML files"),
):
"""Export metric definitions from DuckDB to YAML files (direct, no API)."""
from src.db import get_system_db
from src.repositories.metrics import MetricRepository
conn = get_system_db()
try:
repo = MetricRepository(conn)
count = repo.export_to_yaml(output_dir)
typer.echo(f"Exported {count} metric(s) to {output_dir}")
finally:
conn.close()
@admin_metrics_app.command("validate")
def validate_metrics():
"""Check each metric's table reference against registered tables (direct, no API)."""
from src.db import get_system_db
from src.repositories.metrics import MetricRepository
from src.repositories.table_registry import TableRegistryRepository
conn = get_system_db()
try:
metric_repo = MetricRepository(conn)
registry_repo = TableRegistryRepository(conn)
metrics = metric_repo.list()
registered_tables = {t["name"] for t in registry_repo.list_all()}
ok_count = 0
warn_count = 0
for m in metrics:
name = m.get("name", m.get("id", "?"))
table = m.get("table_name")
if not table:
typer.echo(f" OK {name:30s} (no table reference)")
ok_count += 1
elif table in registered_tables:
typer.echo(f" OK {name:30s} table={table}")
ok_count += 1
else:
typer.echo(f" WARN {name:30s} table={table} (not registered)")
warn_count += 1
typer.echo(f"\nTotal: {len(metrics)} metric(s) — {ok_count} OK, {warn_count} WARN")
if warn_count > 0:
raise typer.Exit(1)
finally:
conn.close()