"""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()