Files
cleveragents-core/benchmarks/checkpoint_rollback_bench.py
brent.edwards 34c6972a05
CI / build (push) Successful in 18s
CI / lint (push) Successful in 3m20s
CI / typecheck (push) Successful in 3m56s
CI / benchmark-regression (push) Has been skipped
CI / security (push) Successful in 4m1s
CI / quality (push) Successful in 4m8s
CI / unit_tests (push) Successful in 6m40s
CI / integration_tests (push) Successful in 6m40s
CI / docker (push) Successful in 1m19s
CI / e2e_tests (push) Failing after 17m17s
CI / coverage (push) Failing after 18m20s
CI / benchmark-publish (push) Successful in 31m37s
CI / status-check (push) Failing after 1s
feat(tool): implement BuiltinAdapter class and MCP automatic resource slot creation (#964)
## Summary

Implement `BuiltinAdapter` class and MCP automatic resource slot creation. Two main changes:

### 1. BuiltinAdapter Class (`tool/builtins/adapter.py`)
Formal adapter implementing the tool adapter lifecycle pattern for built-in tools:
- `discover()` — returns all built-in tool descriptors (file, git, subplan tools)
- `register(registry)` — registers all tools in a ToolRegistry, returns registered names
- `activate()`/`deactivate()` — no-ops (built-in tools are always available)
- Wraps existing `ALL_FILE_TOOLS`, `ALL_GIT_TOOLS`, `ALL_SUBPLAN_TOOLS` lists
- Backward compatible — existing registration functions still work

### 2. MCP Resource Slot Inference (`mcp/adapter.py`)
New `infer_resource_slots()` static method on `MCPToolAdapter`:
- Scans MCP tool parameter schemas for file/directory/repo patterns
- Creates `ResourceSlot` objects with appropriate type, access mode, binding mode
- Mapping: `file_path`→file(rw), `directory`→directory(ro), `repo_path`→git-checkout(rw)
- Slots stored in `source_metadata["resource_slots"]` on registered `ToolSpec` objects

### Quality Gates

| Session | Result |
|---|---|
| `nox -s lint` | PASS |
| `nox -s typecheck` | PASS (0 errors) |
| `nox -s unit_tests` | PASS (10,817 scenarios) |
| `nox -s integration_tests` | PASS (6 new tests) |
| `nox -s coverage_report` | 97% (>= 97%) |

Closes #882

Reviewed-on: #964
Co-authored-by: Brent E. Edwards <brent.edwards@cleverthis.com>
Co-committed-by: Brent E. Edwards <brent.edwards@cleverthis.com>
2026-03-21 05:30:01 +00:00

150 lines
4.9 KiB
Python

"""Airspeed Velocity benchmarks for checkpoint and rollback operations.
Measures checkpoint creation, listing, rollback, pruning, and metadata
overhead across varying checkpoint counts.
"""
from __future__ import annotations
import shutil
import subprocess
import tempfile
from typing import ClassVar
from cleveragents.application.services.checkpoint_service import CheckpointService
from cleveragents.domain.models.core.checkpoint import CheckpointRetentionPolicy
_PLAN_ID = "01ARZ3NDEKTSV4RRFFQ69G5FAV"
# ---------------------------------------------------------------------------
# Checkpoint creation benchmarks
# ---------------------------------------------------------------------------
class CheckpointCreateSuite:
"""Benchmark checkpoint creation at varying counts."""
def setup(self) -> None:
"""Prepare a fresh service instance."""
self.svc = CheckpointService()
def time_create_single(self) -> None:
"""Time creating a single checkpoint."""
self.svc.create_checkpoint(_PLAN_ID, "commit-abc")
def time_create_ten(self) -> None:
"""Time creating 10 checkpoints."""
svc = CheckpointService()
for i in range(10):
svc.create_checkpoint(_PLAN_ID, f"commit-{i}")
def time_create_hundred(self) -> None:
"""Time creating 100 checkpoints."""
svc = CheckpointService()
for i in range(100):
svc.create_checkpoint(_PLAN_ID, f"commit-{i}")
# ---------------------------------------------------------------------------
# Checkpoint listing benchmarks
# ---------------------------------------------------------------------------
class CheckpointListSuite:
"""Benchmark listing checkpoints at varying plan sizes."""
params: ClassVar[list[int]] = [10, 50, 100]
param_names: ClassVar[list[str]] = ["checkpoint_count"]
def setup(self, checkpoint_count: int) -> None:
"""Populate service with checkpoints."""
self.svc = CheckpointService()
for i in range(checkpoint_count):
self.svc.create_checkpoint(_PLAN_ID, f"commit-{i}")
def time_list(self, checkpoint_count: int) -> None:
"""Time listing all checkpoints for a plan."""
self.svc.list_checkpoints(_PLAN_ID)
# ---------------------------------------------------------------------------
# Rollback benchmarks
# ---------------------------------------------------------------------------
class RollbackSuite:
"""Benchmark rollback operations."""
def setup(self) -> None:
"""Prepare a service with a real git sandbox and checkpoints."""
self._tmpdir = tempfile.mkdtemp(prefix="asv-rollback-")
subprocess.run(
["git", "init", self._tmpdir],
check=True,
capture_output=True,
)
subprocess.run(
["git", "commit", "--allow-empty", "-m", "initial"],
check=True,
capture_output=True,
cwd=self._tmpdir,
)
self.svc = CheckpointService()
self.svc.register_sandbox(_PLAN_ID, self._tmpdir)
self.cp = self.svc.create_checkpoint(_PLAN_ID, "commit-abc")
def teardown(self) -> None:
"""Remove temporary sandbox directory."""
shutil.rmtree(self._tmpdir, ignore_errors=True)
def time_rollback(self) -> None:
"""Time a single rollback operation."""
self.svc.rollback_to_checkpoint(_PLAN_ID, self.cp.checkpoint_id)
# ---------------------------------------------------------------------------
# Prune benchmarks
# ---------------------------------------------------------------------------
class PruneSuite:
"""Benchmark checkpoint pruning at varying counts."""
params: ClassVar[list[int]] = [20, 50, 100]
param_names: ClassVar[list[str]] = ["checkpoint_count"]
def setup(self, checkpoint_count: int) -> None:
"""Populate service with checkpoints."""
self.svc = CheckpointService()
for i in range(checkpoint_count):
self.svc.create_checkpoint(_PLAN_ID, f"commit-{i}")
def time_prune_to_five(self, checkpoint_count: int) -> None:
"""Time pruning down to 5 checkpoints."""
policy = CheckpointRetentionPolicy(max_checkpoints=5, auto_prune=True)
self.svc.prune_checkpoints(_PLAN_ID, policy)
# ---------------------------------------------------------------------------
# Metadata benchmarks
# ---------------------------------------------------------------------------
class MetadataSuite:
"""Benchmark checkpoint creation with metadata."""
def setup(self) -> None:
"""Prepare service."""
self.svc = CheckpointService()
def time_create_with_metadata(self) -> None:
"""Time creating a checkpoint with full metadata."""
self.svc.create_checkpoint(
_PLAN_ID,
"commit-xyz",
reason="pre-execution snapshot",
source_tool="lint-check",
phase="execute",
)