Files
Jeff (CTO) d98666651f
CI / lint (pull_request) Successful in 15s
CI / typecheck (pull_request) Successful in 27s
CI / security (pull_request) Successful in 22s
CI / quality (pull_request) Successful in 15s
CI / integration_tests (pull_request) Successful in 4m24s
CI / build (pull_request) Successful in 16s
CI / unit_tests (pull_request) Successful in 9m27s
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / security (push) Waiting to run
CI / quality (push) Waiting to run
CI / unit_tests (push) Waiting to run
CI / integration_tests (push) Waiting to run
CI / coverage (push) Blocked by required conditions
CI / build (push) Waiting to run
CI / docker (push) Blocked by required conditions
CI / coverage (pull_request) Successful in 6m55s
CI / docker (pull_request) Successful in 39s
feat(cli): align action commands to spec
- Enforce config-only 'action create --config <file>' (remove legacy
  inline flags: --name, --strategy-actor, --execution-actor,
  --definition-of-done, --arg)
- Load config via ActionConfigSchema.from_yaml_file() then
  Action.from_config() with clear validation error surfacing
- Remove 'action available' subcommand (no draft state; actions are
  available by default)
- Add REGEX positional arg to 'action list' for name filtering
- Add Short Name and Definition of Done summary to all CLI outputs
- Add 'action list --namespace/-n' and '--state/-s' filters
- Update existing tests to match new config-only create flow
- Add features/action_cli_spec_alignment.feature (19 scenarios)
- Add robot/action_cli_spec.robot smoke tests
- Add benchmarks/action_cli_bench.py ASV benchmarks
- Add docs/reference/action_cli.md
2026-02-14 12:16:39 -05:00

135 lines
4.1 KiB
Python

"""ASV benchmarks for Action CLI command throughput.
Measures the performance of:
- Config-only create (YAML load + validate + Action.from_config)
- List command rendering
- Show command rendering
- Archive command rendering
"""
from __future__ import annotations
import importlib
import os
import sys
import tempfile
from datetime import datetime
from pathlib import Path
from unittest.mock import MagicMock, patch
# Ensure the local *source* tree is importable even when ASV has an
# older build of the package installed.
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
import cleveragents # noqa: E402
importlib.reload(cleveragents)
from typer.testing import CliRunner # noqa: E402
from cleveragents.cli.commands.action import app as action_app # noqa: E402
from cleveragents.domain.models.core.action import Action, ActionState # noqa: E402
from cleveragents.domain.models.core.plan import NamespacedName # noqa: E402
_VALID_YAML = """\
name: local/bench-action
description: Benchmark action
strategy_actor: openai/gpt-4
execution_actor: openai/gpt-4
definition_of_done: Benchmarks pass
"""
_runner = CliRunner()
def _mock_action(name: str = "local/bench-action") -> Action:
return Action(
namespaced_name=NamespacedName.parse(name),
description="Benchmark action",
definition_of_done="Benchmarks pass",
strategy_actor="openai/gpt-4",
execution_actor="openai/gpt-4",
state=ActionState.AVAILABLE,
created_at=datetime.now(),
updated_at=datetime.now(),
)
class ActionCLICreateSuite:
"""Benchmark action create --config throughput."""
def setup(self) -> None:
"""Write a temporary YAML file and set up mock service."""
fd, self._path = tempfile.mkstemp(suffix=".yaml")
with os.fdopen(fd, "w") as fh:
fh.write(_VALID_YAML)
self._mock_service = MagicMock()
self._mock_service.create_action.return_value = _mock_action()
self._patcher = patch(
"cleveragents.cli.commands.action._get_lifecycle_service",
return_value=self._mock_service,
)
self._patcher.start()
def teardown(self) -> None:
"""Clean up."""
self._patcher.stop()
Path(self._path).unlink(missing_ok=True)
def time_create_from_config(self) -> None:
"""Benchmark create --config end-to-end."""
_runner.invoke(action_app, ["create", "--config", self._path])
class ActionCLIListSuite:
"""Benchmark action list throughput."""
def setup(self) -> None:
"""Set up mock service with actions."""
self._mock_service = MagicMock()
self._mock_service.list_actions.return_value = [
_mock_action(f"local/action-{i}") for i in range(50)
]
self._patcher = patch(
"cleveragents.cli.commands.action._get_lifecycle_service",
return_value=self._mock_service,
)
self._patcher.start()
def teardown(self) -> None:
self._patcher.stop()
def time_list_all(self) -> None:
"""Benchmark listing all actions."""
_runner.invoke(action_app, ["list"])
def time_list_with_namespace(self) -> None:
"""Benchmark listing with namespace filter."""
_runner.invoke(action_app, ["list", "--namespace", "local"])
def time_list_with_state(self) -> None:
"""Benchmark listing with state filter."""
_runner.invoke(action_app, ["list", "--state", "available"])
class ActionCLIShowSuite:
"""Benchmark action show throughput."""
def setup(self) -> None:
self._mock_service = MagicMock()
self._mock_service.get_action_by_name.return_value = _mock_action()
self._patcher = patch(
"cleveragents.cli.commands.action._get_lifecycle_service",
return_value=self._mock_service,
)
self._patcher.start()
def teardown(self) -> None:
self._patcher.stop()
def time_show(self) -> None:
"""Benchmark showing an action."""
_runner.invoke(action_app, ["show", "local/bench-action"])