Files
cleveragents-core/robot/helper_plan_execute_runtime.py
freemo a2da043cbd
CI / lint (pull_request) Successful in 25s
CI / benchmark-publish (pull_request) Has been skipped
CI / quality (pull_request) Successful in 21s
CI / typecheck (pull_request) Successful in 39s
CI / security (pull_request) Successful in 37s
CI / build (pull_request) Successful in 26s
CI / integration_tests (pull_request) Successful in 4m43s
CI / unit_tests (pull_request) Successful in 11m2s
CI / docker (pull_request) Successful in 58s
CI / benchmark-regression (pull_request) Successful in 18m58s
CI / coverage (pull_request) Successful in 24m24s
feat(M1.2): PlanExecutionContext, RuntimeExecuteActor, and runtime mode
Adds PlanExecutionContext carrying plan metadata and delegating
changeset ops to ChangeSetStore.  RuntimeExecuteResult captures
execution output (changeset_id, tool_call_count, sandbox_refs,
decision_ids_processed, execution_duration_ms).

RuntimeExecuteActor dispatches StrategyDecision lists through
ToolRunner with full changeset capture and optional streaming
callbacks.  PlanExecutor gains execution_context param with
has_runtime / changeset_store / execution_context properties
and _run_execute_with_runtime / _run_execute_with_stub split.

31 Behave scenarios, 5 Robot smoke tests, ASV benchmark suite,
and reference documentation.

Ref: Day-14 Rebaseline – M1.2 Plan-execute runtime wiring [Jeff]
2026-02-22 15:13:43 +00:00

209 lines
5.8 KiB
Python

"""Helper script for plan execute runtime Robot Framework tests.
Dispatches to individual test functions via a COMMANDS dict.
"""
from __future__ import annotations
import sys
from ulid import ULID
from cleveragents.application.services.plan_execution_context import (
PlanExecutionContext,
RuntimeExecuteActor,
RuntimeExecuteResult,
)
from cleveragents.application.services.plan_executor import (
PlanExecutor,
StrategyDecision,
)
from cleveragents.core.exceptions import ValidationError
from cleveragents.domain.models.core.change import (
ChangeEntry,
ChangeOperation,
InMemoryChangeSetStore,
)
from cleveragents.tool.registry import ToolRegistry
from cleveragents.tool.runner import ToolRunner
def _make_runner() -> ToolRunner:
return ToolRunner(registry=ToolRegistry())
def _make_decisions(count: int) -> list[StrategyDecision]:
root_id = str(ULID())
return [
StrategyDecision(
decision_id=root_id if i == 0 else str(ULID()),
step_text=f"Step {i + 1}",
sequence=i,
parent_id=root_id if i > 0 else None,
)
for i in range(count)
]
def _context_creation() -> None:
"""Test PlanExecutionContext creation and defaults."""
plan_id = str(ULID())
ctx = PlanExecutionContext(plan_id=plan_id)
assert ctx.plan_id == plan_id
assert ctx.decision_root_id is None
assert ctx.sandbox_root is None
assert ctx.automation_profile is None
assert ctx.project_resources == {}
assert ctx.resource_bindings == {}
assert isinstance(ctx.changeset_store, InMemoryChangeSetStore)
# With all fields
store = InMemoryChangeSetStore()
ctx2 = PlanExecutionContext(
plan_id=plan_id,
decision_root_id="root-123",
sandbox_root="/tmp/sb",
automation_profile="trusted",
project_resources={"r": "v"},
changeset_store=store,
)
assert ctx2.decision_root_id == "root-123"
assert ctx2.sandbox_root == "/tmp/sb"
assert ctx2.automation_profile == "trusted"
assert ctx2.changeset_store is store
# Empty plan_id should fail
try:
PlanExecutionContext(plan_id="")
raise AssertionError("Expected ValidationError")
except ValidationError:
pass
print("context-creation-ok")
def _changeset_ops() -> None:
"""Test changeset start, record, get, summarize."""
plan_id = str(ULID())
store = InMemoryChangeSetStore()
ctx = PlanExecutionContext(plan_id=plan_id, changeset_store=store)
cs_id = ctx.start_changeset()
assert len(cs_id) == 26 # ULID length
assert cs_id in ctx.active_changeset_ids
entry = ChangeEntry(
plan_id=plan_id,
resource_id=str(ULID()),
tool_name="test/tool",
operation=ChangeOperation.MODIFY,
path="src/test.py",
)
ctx.record_change(entry)
cs = ctx.get_changeset(cs_id)
assert cs is not None
assert len(cs.entries) == 1
assert cs.entries[0].entry_id == entry.entry_id
# Unknown ID
assert ctx.get_changeset("nonexistent") is None
# Summarize
summary = ctx.summarize()
assert summary["plan_id"] == plan_id
assert summary["active_changeset_count"] == 1
assert len(summary["changeset_summaries"]) == 1
print("changeset-ops-ok")
def _runtime_actor() -> None:
"""Test RuntimeExecuteActor execution."""
plan_id = str(ULID())
store = InMemoryChangeSetStore()
ctx = PlanExecutionContext(plan_id=plan_id, changeset_store=store)
runner = _make_runner()
actor = RuntimeExecuteActor(tool_runner=runner, execution_context=ctx)
decisions = _make_decisions(2)
result = actor.execute(decisions=decisions)
assert isinstance(result, RuntimeExecuteResult)
assert len(result.changeset_id) == 26
assert len(result.decision_ids_processed) == 2
assert result.execution_duration_ms >= 0.0
# With stream callback
events: list[tuple[str, dict]] = []
actor2 = RuntimeExecuteActor(tool_runner=runner, execution_context=ctx)
actor2.execute(
decisions=_make_decisions(1),
stream_callback=lambda t, d: events.append((t, d)),
)
types = [e[0] for e in events]
assert "runtime_execute_started" in types
assert "runtime_execute_complete" in types
print("runtime-actor-ok")
def _executor_runtime() -> None:
"""Test PlanExecutor with execution context (runtime mode)."""
plan_id = str(ULID())
store = InMemoryChangeSetStore()
ctx = PlanExecutionContext(plan_id=plan_id, changeset_store=store)
from unittest.mock import MagicMock
lifecycle = MagicMock()
executor = PlanExecutor(
lifecycle_service=lifecycle,
tool_runner=_make_runner(),
execution_context=ctx,
)
assert executor.has_runtime is True
assert executor.changeset_store is store
assert executor.execution_context is ctx
print("executor-runtime-ok")
def _executor_stub() -> None:
"""Test PlanExecutor without execution context (stub mode)."""
from unittest.mock import MagicMock
lifecycle = MagicMock()
executor = PlanExecutor(lifecycle_service=lifecycle)
assert executor.has_runtime is False
assert executor.changeset_store is None
assert executor.execution_context is None
print("executor-stub-ok")
COMMANDS: dict[str, object] = {
"context-creation": _context_creation,
"changeset-ops": _changeset_ops,
"runtime-actor": _runtime_actor,
"executor-runtime": _executor_runtime,
"executor-stub": _executor_stub,
}
def main() -> None:
if len(sys.argv) < 2:
raise SystemExit("Expected command argument")
command = sys.argv[1]
if command not in COMMANDS:
raise SystemExit(f"Unknown command: {command}")
func = COMMANDS[command]
if callable(func):
func()
if __name__ == "__main__":
main()