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]
7.8 KiB
Plan Execute: Strategize & Execute Integration
Overview
The plan executor connects the PlanLifecycleService to stub actors that
drive plans through the Strategize and Execute phases. In M1, these
actors are local-only stubs (no LLM calls); future milestones will integrate
real AI providers.
When a PlanExecutionContext is provided, the execute phase delegates to
RuntimeExecuteActor for full tool-calling runtime integration with
changeset capture through ChangeSetStore.
Architecture
PlanExecutor
├── StrategizeStubActor (read-only, produces decision tree)
├── ExecuteStubActor (legacy stub: sandbox + ChangeSetCapture)
├── RuntimeExecuteActor (runtime: ToolRunner + ChangeSetStore)
├── PlanExecutionContext (plan metadata + resource bindings)
└── PlanLifecycleService (phase transitions, persistence)
Execution Modes
| Mode | Actor | Trigger | Output |
|---|---|---|---|
| Stub | ExecuteStubActor | No execution_context |
ExecuteResult |
| Runtime | RuntimeExecuteActor | execution_context is provided |
RuntimeExecuteResult |
PlanExecutionContext
The PlanExecutionContext bridges plan metadata into the tool runtime:
from cleveragents.application.services.plan_execution_context import (
PlanExecutionContext,
)
from cleveragents.domain.models.core.change import InMemoryChangeSetStore
ctx = PlanExecutionContext(
plan_id="01HGZ...",
decision_root_id="01HGZ...",
sandbox_root="/tmp/sandbox",
automation_profile="trusted",
project_resources={"repo": {"path": "/code"}},
changeset_store=InMemoryChangeSetStore(),
)
# Start a changeset for tracking mutations
changeset_id = ctx.start_changeset()
# Record changes during execution
ctx.record_change(entry)
# Retrieve changeset
cs = ctx.get_changeset(changeset_id)
# Summarize context state
summary = ctx.summarize()
Fields
| Field | Type | Required | Description |
|---|---|---|---|
plan_id |
str |
Yes | ULID of the plan |
decision_root_id |
str | None |
No | Root decision from strategize |
sandbox_root |
str | None |
No | Sandbox filesystem path |
automation_profile |
str | None |
No | Automation profile name |
project_resources |
dict[str, Any] |
No | Project resource metadata |
resource_bindings |
dict[str, BoundResource] |
No | Resolved resource bindings |
changeset_store |
ChangeSetStore |
No | Defaults to InMemoryChangeSetStore |
RuntimeExecuteActor
Wraps ToolRunner to execute strategy decisions with changeset capture:
from cleveragents.application.services.plan_execution_context import (
RuntimeExecuteActor,
RuntimeExecuteResult,
)
actor = RuntimeExecuteActor(
tool_runner=runner,
execution_context=ctx,
)
result: RuntimeExecuteResult = actor.execute(decisions)
RuntimeExecuteResult Fields
| Field | Type | Description |
|---|---|---|
changeset_id |
str |
ULID of the produced changeset |
tool_call_count |
int |
Number of tool calls made |
sandbox_refs |
list[str] |
Sandbox reference paths |
decision_ids_processed |
list[str] |
Processed decision node IDs |
execution_duration_ms |
float |
Wall-clock execution time (ms) |
PlanExecutor Runtime Mode
The PlanExecutor auto-selects runtime vs stub mode:
from cleveragents.application.services.plan_executor import PlanExecutor
# Stub mode (no execution_context)
executor = PlanExecutor(lifecycle_service=lifecycle, tool_runner=runner)
assert not executor.has_runtime
# Runtime mode (with execution_context)
executor = PlanExecutor(
lifecycle_service=lifecycle,
tool_runner=runner,
execution_context=ctx,
)
assert executor.has_runtime
assert executor.changeset_store is not None
# Execute auto-dispatches to RuntimeExecuteActor
result = executor.run_execute(plan_id)
Properties
| Property | Type | Description |
|---|---|---|
has_runtime |
bool |
True if execution_context is set |
changeset_store |
ChangeSetStore | None |
Store from execution context |
execution_context |
PlanExecutionContext | None |
The execution context |
ChangeSetStore Wiring
The ChangeSetStore protocol defines the interface for changeset persistence:
class ChangeSetStore(Protocol):
def start(self, plan_id: str) -> str: ...
def record(self, changeset_id: str, entry: ChangeEntry) -> None: ...
def get(self, changeset_id: str) -> SpecChangeSet | None: ...
def get_for_plan(self, plan_id: str) -> list[SpecChangeSet]: ...
def summarize(self, changeset_id: str) -> dict[str, Any]: ...
InMemoryChangeSetStore is the default for M1. Database-backed
implementations will be added in D1 milestone.
Phase Lifecycle
| Phase | Actor | Mode | Output |
|---|---|---|---|
| Strategize | StrategizeStubActor | Read-only | Decision tree, invariant records |
| Execute | RuntimeExecuteActor | Runtime | ChangeSet via ChangeSetStore |
| Execute | ExecuteStubActor | Stub | ChangeSet via ChangeSetCapture |
Error Handling
Failures in either phase are captured with full error context:
error_message: The exception message stringerror_details: Dict withexception_type,traceback, andmode- The plan transitions to
ERROREDprocessing state
Streaming Hooks
Both phases accept an optional stream_callback:
Event Types
| Event | Phase | Actor | Description |
|---|---|---|---|
strategize_started |
Strat. | Stub | Phase processing began |
strategize_decisions |
Strat. | Stub | Decisions produced |
strategize_complete |
Strat. | Stub | Phase completed |
execute_started |
Execute | Stub | Stub execute began |
execute_step |
Execute | Stub | Stub decision step |
execute_complete |
Execute | Stub | Stub execute completed |
runtime_execute_started |
Execute | Runtime | Runtime execute began |
runtime_execute_step |
Execute | Runtime | Runtime decision step |
runtime_execute_complete |
Execute | Runtime | Runtime execute completed |
Module Reference
cleveragents.application.services.plan_execution_contextPlanExecutionContext: Execution context bridging plan to runtimeRuntimeExecuteActor: Tool-calling execute actorRuntimeExecuteResult: Runtime execution output model
cleveragents.application.services.plan_executorPlanExecutor: Orchestrator with runtime/stub mode selectionStrategizeStubActor: Local-only strategize actorExecuteStubActor: Local-only execute actorStrategyDecision,StrategizeResult,ExecuteResult: Data models