Skip to content

Commit a94a5e9

Browse files
committed
read generatedAt and lastUpdated fields and show them in list
Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
1 parent 05e3aac commit a94a5e9

4 files changed

Lines changed: 54 additions & 10 deletions

File tree

examples/custom_evaluators/eval_config.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ evaluators:
2626
min_response_length: 20
2727

2828
# Reference an evaluator from Github
29-
- name: peters_evaluator
29+
- name: random_evaluator
3030
type: remote
3131
source: github
32-
ref: evaluators/peters_evaluator/peters_evaluator.py
32+
ref: evaluators/random_evaluator/random_evaluator.py
3333
threshold: 0.110
3434
executor: local
35+

src/agentevals/cli.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,43 @@
1414
import logging
1515
import os
1616
import sys
17+
from datetime import datetime, timezone
1718

1819
import click
1920

2021
from . import __version__
2122

2223

24+
def _relative_time(iso_str: str | None) -> str:
25+
"""Format an ISO 8601 timestamp as a human-readable relative time string."""
26+
if not iso_str:
27+
return ""
28+
try:
29+
dt = datetime.fromisoformat(iso_str.replace("Z", "+00:00"))
30+
delta = datetime.now(timezone.utc) - dt
31+
seconds = int(delta.total_seconds())
32+
if seconds < 0:
33+
return "just now"
34+
if seconds < 60:
35+
return f"{seconds}s ago"
36+
minutes = seconds // 60
37+
if minutes < 60:
38+
return f"{minutes}m ago"
39+
hours = minutes // 60
40+
if hours < 24:
41+
return f"{hours}h ago"
42+
days = hours // 24
43+
if days < 30:
44+
return f"{days}d ago"
45+
months = days // 30
46+
if months < 12:
47+
return f"{months}mo ago"
48+
years = days // 365
49+
return f"{years}y ago"
50+
except (ValueError, TypeError):
51+
return ""
52+
53+
2354
@click.group()
2455
@click.version_option(version=__version__, prog_name="agentevals")
2556
@click.option(
@@ -314,21 +345,32 @@ def evaluator_list(source: str, refresh: bool) -> None:
314345
max_name = max(len(g.name) for g in all_evaluators)
315346
max_src = max(len(g.source) for g in all_evaluators)
316347

348+
has_updated = any(g.last_updated for g in all_evaluators)
349+
updated_col_width = 10 if has_updated else 0
350+
317351
try:
318352
term_width = os.get_terminal_size().columns
319353
except OSError:
320354
term_width = 120
321-
desc_width = max(20, term_width - max_name - max_src - 8)
322355

323-
click.echo(f" {'NAME':<{max_name}} {'SOURCE':<{max_src}} DESCRIPTION")
324-
click.echo(f" {'-' * max_name} {'-' * max_src} {'-' * min(40, desc_width)}")
356+
overhead = max_name + max_src + 8
357+
if has_updated:
358+
overhead += updated_col_width + 2
359+
desc_width = max(20, term_width - overhead)
360+
361+
hdr_updated = f" {'UPDATED':<{updated_col_width}}" if has_updated else ""
362+
sep_updated = f" {'-' * updated_col_width}" if has_updated else ""
363+
364+
click.echo(f" {'NAME':<{max_name}} {'SOURCE':<{max_src}}{hdr_updated} DESCRIPTION")
365+
click.echo(f" {'-' * max_name} {'-' * max_src}{sep_updated} {'-' * min(40, desc_width)}")
325366

326367
for g in sorted(all_evaluators, key=lambda x: (x.source, x.name)):
327368
lang = f" [{g.language}]" if g.language else ""
328369
desc = g.description + lang
329370
if len(desc) > desc_width:
330371
desc = desc[: desc_width - 3] + "..."
331-
click.echo(f" {g.name:<{max_name}} {g.source:<{max_src}} {desc}")
372+
col_updated = f" {_relative_time(g.last_updated):<{updated_col_width}}" if has_updated else ""
373+
click.echo(f" {g.name:<{max_name}} {g.source:<{max_src}}{col_updated} {desc}")
332374

333375
click.echo(f"\n {len(all_evaluators)} evaluator(s) found.")
334376

src/agentevals/evaluator/sources.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class EvaluatorInfo:
3030
ref: str | None = None
3131
tags: list[str] = field(default_factory=list)
3232
author: str | None = None
33+
last_updated: str | None = None
3334

3435

3536
class EvaluatorSource(abc.ABC):
@@ -200,6 +201,7 @@ async def list_evaluators(self) -> list[EvaluatorInfo]:
200201
ref=entry.get("path"),
201202
tags=entry.get("tags", []),
202203
author=entry.get("author"),
204+
last_updated=entry.get("lastUpdated"),
203205
)
204206
)
205207
return infos
@@ -252,6 +254,7 @@ async def list_evaluators(self) -> list[EvaluatorInfo]:
252254
ref=entry.get("path"),
253255
tags=entry.get("tags", []),
254256
author=entry.get("author"),
257+
last_updated=entry.get("lastUpdated"),
255258
)
256259
)
257260
return infos

uv.lock

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)