-
Notifications
You must be signed in to change notification settings - Fork 0
SDK-91: Refactor CLI into modular subcommands for eval, unlearning, and dataset-qa #227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f3481d5
7b375da
43afadc
d235f6b
f1a4e0f
23e9cc8
36663cf
63c2723
cc2e8bf
67dc58a
474d44a
95812ac
9a4feff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| .. meta:: | ||
| :http-equiv=Content-Security-Policy: default-src 'self', frame-ancestors 'none' | ||
|
|
||
| hirundo.cli_dataset_qa module | ||
| ============================= | ||
|
|
||
| .. automodule:: hirundo.cli_dataset_qa | ||
| :members: | ||
| :undoc-members: | ||
| :show-inheritance: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| .. meta:: | ||
| :http-equiv=Content-Security-Policy: default-src 'self', frame-ancestors 'none' | ||
|
|
||
| hirundo.cli_eval module | ||
| ======================= | ||
|
|
||
| .. automodule:: hirundo.cli_eval | ||
| :members: | ||
| :undoc-members: | ||
| :show-inheritance: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| .. meta:: | ||
| :http-equiv=Content-Security-Policy: default-src 'self', frame-ancestors 'none' | ||
|
|
||
| hirundo.cli_unlearning module | ||
| ============================= | ||
|
|
||
| .. automodule:: hirundo.cli_unlearning | ||
| :members: | ||
| :undoc-members: | ||
| :show-inheritance: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import re | ||
| import sys | ||
| from collections.abc import Callable | ||
| from enum import Enum | ||
| from typing import Any | ||
|
|
||
| import typer | ||
| from rich.console import Console | ||
| from rich.table import Table | ||
|
|
||
| _RUN_ID_RE = re.compile(r"^[a-zA-Z0-9_-]+$") | ||
|
|
||
| docs = "sphinx" in sys.modules | ||
| hirundo_epilog = ( | ||
| None | ||
| if docs | ||
| else "Made with ❤️ by Hirundo. Visit https://www.hirundo.io for more information." | ||
| ) | ||
|
|
||
| console = Console() | ||
|
|
||
|
|
||
| def make_app(name: str, help_text: str) -> typer.Typer: | ||
| return typer.Typer( | ||
| name=name, | ||
| no_args_is_help=True, | ||
| rich_markup_mode="rich", | ||
| epilog=hirundo_epilog, | ||
| help=help_text, | ||
| ) | ||
|
|
||
|
|
||
| def validate_run_id(run_id: str) -> str: | ||
| if not _RUN_ID_RE.fullmatch(run_id): | ||
| console.print( | ||
| f"[red]Invalid run ID '{run_id}'. " | ||
| "Run IDs may only contain alphanumeric characters, hyphens, and underscores.[/red]" | ||
| ) | ||
| raise typer.Exit(code=1) from None | ||
| return run_id | ||
|
|
||
|
|
||
| def validate_enum(value: str, enum_cls: type[Enum], label: str) -> Any: | ||
| try: | ||
| return enum_cls(value.upper()) | ||
| except ValueError: | ||
| valid = ", ".join(member.value for member in enum_cls) | ||
| console.print(f"[red]Invalid {label} '{value}'. Valid options: {valid}[/red]") | ||
| raise typer.Exit(code=1) from None | ||
|
|
||
|
|
||
| def wait_or_notify( | ||
| run_id: str, check_fn: Callable[[str], Any], cmd_name: str, wait: bool | ||
| ) -> Any: | ||
| if wait: | ||
| return check_fn(run_id) | ||
| console.print( | ||
| f"Use [bold]hirundo {cmd_name} check[/bold] [italic]<run_id>[/italic] to monitor progress." | ||
| ) | ||
| return None | ||
|
Comment on lines
+52
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Finding type: Prompt for AI Agents: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commit 9a4feff addressed this comment by adding focused tests for wait_or_notify, covering the wait=True return propagation and the wait=False console prompt/hint output. |
||
|
|
||
|
|
||
| def print_runs_table( | ||
| title: str, | ||
| columns: tuple[str, ...], | ||
| rows: list[tuple[str | None, ...]], | ||
| ) -> None: | ||
| table = Table(title=title, expand=True) | ||
| for col in columns: | ||
| table.add_column(col, overflow="fold") | ||
| for row in rows: | ||
| table.add_row(*row) | ||
| console.print(table) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| from typing import Annotated | ||
|
|
||
| import typer | ||
|
|
||
| from hirundo._cli_common import ( | ||
| console, | ||
| hirundo_epilog, | ||
| make_app, | ||
| print_runs_table, | ||
| validate_run_id, | ||
| wait_or_notify, | ||
| ) | ||
|
|
||
| dataset_qa_app = make_app("dataset-qa", "Launch and monitor Dataset QA runs.") | ||
|
|
||
|
|
||
| @dataset_qa_app.command("run", epilog=hirundo_epilog) | ||
| def dataset_qa_run( | ||
| dataset_id: Annotated[int, typer.Argument(help="ID of the dataset to run QA on.")], | ||
| wait: Annotated[ | ||
| bool, | ||
| typer.Option( | ||
| "--wait/--no-wait", help="Wait for the run to complete and stream progress." | ||
| ), | ||
| ] = True, | ||
| ): | ||
| """ | ||
| Launch a Dataset QA run on the dataset with the given ID. | ||
| """ | ||
| from hirundo.dataset_qa import QADataset | ||
|
|
||
| run_id = QADataset.launch_qa_run(dataset_id) | ||
| console.print(f"Dataset QA run started. Run ID: [bold]{run_id}[/bold]") | ||
|
|
||
| results = wait_or_notify(run_id, QADataset.check_run_by_id, "dataset-qa", wait) | ||
| if results is not None: | ||
| console.print(f"Run results saved to {results.cached_zip_path}") | ||
|
|
||
|
|
||
| @dataset_qa_app.command("list", epilog=hirundo_epilog) | ||
| def dataset_qa_list( | ||
| archived: Annotated[ | ||
| bool, | ||
| typer.Option("--archived/--no-archived", help="Include archived runs."), | ||
| ] = False, | ||
| ): | ||
| """ | ||
| List Dataset QA runs. | ||
| """ | ||
| from hirundo.dataset_qa import QADataset | ||
|
|
||
| runs = QADataset.list_runs(archived=archived) | ||
| print_runs_table( | ||
| "Dataset QA Runs:", | ||
| ("Dataset Name", "Run ID", "Status", "Created At", "Run Args"), | ||
| [ | ||
|
Comment on lines
+52
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Finding type: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commit 9a4feff addressed this comment by importing |
||
| ( | ||
| str(run.name), | ||
| str(run.run_id), | ||
| str(run.status), | ||
| run.created_at.isoformat(), | ||
| run.run_args.model_dump_json() if run.run_args else None, | ||
| ) | ||
| for run in runs | ||
| ], | ||
| ) | ||
|
|
||
|
|
||
| @dataset_qa_app.command("check", epilog=hirundo_epilog) | ||
| def dataset_qa_check( | ||
| run_id: Annotated[str, typer.Argument(help="The run ID to check.")], | ||
| ): | ||
| """ | ||
| Check the status of a Dataset QA run and stream progress. | ||
| """ | ||
| from hirundo.dataset_qa import QADataset | ||
|
|
||
| results = QADataset.check_run_by_id(validate_run_id(run_id)) | ||
| if results is not None: | ||
| console.print(f"Run results saved to {results.cached_zip_path}") | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
validate_run_id()usesmatch()which can accept trailing newlines — should we switch tofullmatch(), and add unit tests intests/test_cli_common.pycovering valid/invalid inputs?Finding types:
Breaking ChangesAdd tests for behavior| Severity: 🟢 LowPrompt for AI Agents:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commit 67dc58a addressed this comment by switching
validate_run_idto rely on_RUN_ID_RE.fullmatch, ensuring trailing newlines no longer slip through; the requested tests for valid/invalid inputs still need to be added.