Files
cleveragents-core/docs/reference/plan_execute.md
T
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

196 lines
7.8 KiB
Markdown

# 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:
```python
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:
```python
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:
```python
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:
```python
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 string
- `error_details`: Dict with `exception_type`, `traceback`, and `mode`
- The plan transitions to `ERRORED` processing 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_context`**
- `PlanExecutionContext`: Execution context bridging plan to runtime
- `RuntimeExecuteActor`: Tool-calling execute actor
- `RuntimeExecuteResult`: Runtime execution output model
- **`cleveragents.application.services.plan_executor`**
- `PlanExecutor`: Orchestrator with runtime/stub mode selection
- `StrategizeStubActor`: Local-only strategize actor
- `ExecuteStubActor`: Local-only execute actor
- `StrategyDecision`, `StrategizeResult`, `ExecuteResult`: Data models