Files
cleveragents-core/benchmarks/db_migration_action_args_bench.py
T
freemo 9b30421b34
CI / lint (pull_request) Successful in 16s
CI / typecheck (pull_request) Successful in 27s
CI / security (pull_request) Successful in 21s
CI / quality (pull_request) Successful in 16s
CI / integration_tests (pull_request) Successful in 4m10s
CI / build (pull_request) Successful in 15s
CI / unit_tests (pull_request) Successful in 8m0s
CI / docker (pull_request) Successful in 40s
CI / coverage (pull_request) Successful in 6m22s
CI / lint (push) Successful in 13s
CI / typecheck (push) Successful in 27s
CI / security (push) Successful in 22s
CI / quality (push) Successful in 15s
CI / integration_tests (push) Successful in 4m16s
CI / build (push) Successful in 15s
CI / unit_tests (push) Successful in 8m2s
CI / docker (push) Successful in 39s
CI / coverage (push) Successful in 6m23s
feat(db): add spec-aligned action and plan tables with migrations, ORM models, and benchmarks
2026-02-13 13:05:20 -05:00

170 lines
5.8 KiB
Python

"""ASV benchmarks for action_arguments table ORM round-trip performance.
Measures the performance of:
- ActionArgument construction and serialization for ORM child rows
- Bulk argument serialization for actions with many arguments
- ActionArgumentModel construction patterns
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
try:
from cleveragents.domain.models.core.action import (
Action,
ActionArgument,
ArgumentRequirement,
ArgumentType,
)
from cleveragents.domain.models.core.plan import NamespacedName
from cleveragents.infrastructure.database.models import (
ActionArgumentModel,
LifecycleActionModel,
)
except ModuleNotFoundError:
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cleveragents.domain.models.core.action import (
Action,
ActionArgument,
ArgumentRequirement,
ArgumentType,
)
from cleveragents.domain.models.core.plan import NamespacedName
from cleveragents.infrastructure.database.models import (
ActionArgumentModel,
LifecycleActionModel,
)
def _make_argument(name: str, idx: int) -> ActionArgument:
"""Create a typed argument cycling through types by index."""
types = list(ArgumentType)
arg_type = types[idx % len(types)]
return ActionArgument(
name=name,
arg_type=arg_type,
requirement=ArgumentRequirement.REQUIRED
if idx % 2 == 0
else ArgumentRequirement.OPTIONAL,
description=f"Argument {name} for benchmarking",
default_value="default" if idx % 2 == 1 else None,
min_value=0 if arg_type == ArgumentType.INTEGER else None,
max_value=100 if arg_type == ArgumentType.INTEGER else None,
validation_pattern=r"^[a-z]+$" if arg_type == ArgumentType.STRING else None,
)
def _make_action_with_n_args(n: int) -> Action:
"""Create an action with N arguments."""
return Action(
namespaced_name=NamespacedName(
server=None, namespace="local", name=f"multi-arg-{n}"
),
description=f"Action with {n} arguments",
definition_of_done="All args validated",
strategy_actor="openai/gpt-4",
execution_actor="openai/gpt-4",
arguments=[_make_argument(f"arg_{i}", i) for i in range(n)],
)
class ArgumentModelConstructionSuite:
"""Benchmark ActionArgumentModel construction patterns."""
def setup(self) -> None:
self.args = [_make_argument(f"arg_{i}", i) for i in range(20)]
def time_construct_single_model(self) -> None:
"""Construct a single ActionArgumentModel from values."""
arg = self.args[0]
ActionArgumentModel(
action_name="local/bench-action",
name=arg.name,
arg_type=arg.arg_type.value,
requirement=arg.requirement.value,
description=arg.description,
default_value_json=json.dumps(arg.default_value)
if arg.default_value is not None
else None,
min_value=arg.min_value,
max_value=arg.max_value,
validation_pattern=arg.validation_pattern,
position=0,
)
def time_construct_20_models(self) -> None:
"""Construct 20 ActionArgumentModel instances."""
for i, arg in enumerate(self.args):
ActionArgumentModel(
action_name="local/bench-action",
name=arg.name,
arg_type=arg.arg_type.value,
requirement=arg.requirement.value,
description=arg.description,
default_value_json=json.dumps(arg.default_value)
if arg.default_value is not None
else None,
min_value=arg.min_value,
max_value=arg.max_value,
validation_pattern=arg.validation_pattern,
position=i,
)
class ArgumentRoundTripSuite:
"""Benchmark action ORM round-trip with varying argument counts."""
def setup(self) -> None:
self.action_2_args = _make_action_with_n_args(2)
self.action_10_args = _make_action_with_n_args(10)
self.action_20_args = _make_action_with_n_args(20)
def time_round_trip_2_args(self) -> None:
"""Round-trip an action with 2 arguments through ORM."""
model = LifecycleActionModel.from_domain(self.action_2_args)
model.to_domain()
def time_round_trip_10_args(self) -> None:
"""Round-trip an action with 10 arguments through ORM."""
model = LifecycleActionModel.from_domain(self.action_10_args)
model.to_domain()
def time_round_trip_20_args(self) -> None:
"""Round-trip an action with 20 arguments through ORM."""
model = LifecycleActionModel.from_domain(self.action_20_args)
model.to_domain()
class ArgumentSerializationSuite:
"""Benchmark JSON serialization of argument default values."""
def setup(self) -> None:
self.string_val = "default-string-value"
self.int_val = 42
self.float_val = 3.14159
self.bool_val = True
self.list_val = ["alpha", "beta", "gamma", "delta"]
def time_serialize_string(self) -> None:
"""Serialize a string default value to JSON."""
json.dumps(self.string_val)
def time_serialize_integer(self) -> None:
"""Serialize an integer default value to JSON."""
json.dumps(self.int_val)
def time_serialize_list(self) -> None:
"""Serialize a list default value to JSON."""
json.dumps(self.list_val)
def time_deserialize_string(self) -> None:
"""Deserialize a JSON string default value."""
json.loads('"default-string-value"')
def time_deserialize_list(self) -> None:
"""Deserialize a JSON list default value."""
json.loads('["alpha", "beta", "gamma", "delta"]')