140 lines
4.7 KiB
Markdown
140 lines
4.7 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.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
PlanExecutor
|
|
├── StrategizeStubActor (read-only, produces decision tree)
|
|
├── ExecuteStubActor (sandbox + ToolRunner + ChangeSet capture)
|
|
└── PlanLifecycleService (phase transitions, persistence)
|
|
```
|
|
|
|
## Phase Lifecycle
|
|
|
|
| Phase | Actor | Mode | Output |
|
|
|-------------|---------------------|-----------|---------------------------------|
|
|
| Strategize | StrategizeStubActor | Read-only | Decision tree, invariant records|
|
|
| Execute | ExecuteStubActor | Sandbox | ChangeSet, execution metadata |
|
|
|
|
## Strategize Phase
|
|
|
|
The strategize phase is **read-only**: it produces a decision tree from the
|
|
action's `definition_of_done` without modifying any resources.
|
|
|
|
### Decision Tree
|
|
|
|
The stub actor parses `definition_of_done` into discrete steps, each
|
|
represented as a `StrategyDecision` node with a ULID identifier:
|
|
|
|
```python
|
|
from cleveragents.application.services.plan_executor import (
|
|
PlanExecutor,
|
|
StrategizeResult,
|
|
)
|
|
|
|
executor = PlanExecutor(lifecycle_service=lifecycle, tool_runner=runner)
|
|
result: StrategizeResult = executor.run_strategize(plan_id)
|
|
|
|
# result.decision_root_id -> ULID of root node
|
|
# result.decisions -> list[StrategyDecision]
|
|
# result.invariant_records -> list[dict] (stub enforcement records)
|
|
```
|
|
|
|
### Invariant Propagation
|
|
|
|
Project and action invariants are propagated into the strategize context.
|
|
In M1, enforcement is stubbed (all invariants are accepted). Full
|
|
reconciliation via the Invariant Reconciliation Actor lands in D2.
|
|
|
|
## Execute Phase
|
|
|
|
The execute phase uses sandbox resources with tool calls routed through
|
|
`ToolRunner` and captured by `ChangeSetCapture`.
|
|
|
|
### ChangeSet Capture
|
|
|
|
All tool mutations during execute are recorded in a `ChangeSet`:
|
|
|
|
```python
|
|
result: ExecuteResult = executor.run_execute(plan_id)
|
|
|
|
# result.changeset_id -> ULID of the changeset
|
|
# result.changeset -> ChangeSet with entries
|
|
# result.tool_calls_count -> int
|
|
# result.sandbox_refs -> list[str]
|
|
```
|
|
|
|
### Metadata Persistence
|
|
|
|
After execute completes, the following metadata is persisted on the Plan:
|
|
|
|
- `changeset_id`: The ChangeSet identifier
|
|
- `sandbox_refs`: List of sandbox reference paths
|
|
- `error_details`: Tool call count and sandbox ref count
|
|
|
|
## Phase Guards
|
|
|
|
- **Execute requires Strategize COMPLETE**: The executor validates that the
|
|
plan has completed strategize (has a `decision_root_id`) before allowing
|
|
execute to proceed.
|
|
- **Phase validation**: Both `run_strategize()` and `run_execute()` verify
|
|
the plan is in the correct phase before proceeding.
|
|
|
|
## Error Handling
|
|
|
|
Failures in either phase are captured with full error context:
|
|
|
|
- `error_message`: The exception message string
|
|
- `error_details`: Dict containing `exception_type` and `traceback`
|
|
- The plan transitions to `ERRORED` processing state
|
|
|
|
### Retry Guidance
|
|
|
|
Plans in `ERRORED` state can be retried by:
|
|
|
|
1. Resetting the plan's processing state back to `QUEUED`
|
|
2. Re-running the failed phase via the executor
|
|
|
|
Full retry automation is planned for D1b (Phase Reversion & Error Recovery).
|
|
|
|
## Streaming Hooks
|
|
|
|
Both phases accept an optional `stream_callback` parameter for real-time
|
|
status updates (used by the `--stream` CLI flag):
|
|
|
|
```python
|
|
def my_callback(event_type: str, data: dict) -> None:
|
|
print(f"[{event_type}] {data}")
|
|
|
|
executor.run_strategize(plan_id, stream_callback=my_callback)
|
|
```
|
|
|
|
### Event Types
|
|
|
|
| Event | Phase | Description |
|
|
|------------------------|------------|---------------------------------|
|
|
| `strategize_started` | Strategize | Phase processing began |
|
|
| `strategize_decisions` | Strategize | Decisions produced |
|
|
| `strategize_complete` | Strategize | Phase completed successfully |
|
|
| `execute_started` | Execute | Phase processing began |
|
|
| `execute_step` | Execute | Individual decision being executed |
|
|
| `execute_complete` | Execute | Phase completed successfully |
|
|
|
|
## Module Reference
|
|
|
|
- **`cleveragents.application.services.plan_executor`**: Core module
|
|
- `StrategizeStubActor`: Local-only strategize actor
|
|
- `ExecuteStubActor`: Local-only execute actor
|
|
- `PlanExecutor`: Orchestrator connecting lifecycle service to actors
|
|
- `StrategyDecision`: Decision node model
|
|
- `StrategizeResult`: Strategize output model
|
|
- `ExecuteResult`: Execute output model
|
|
- `StreamCallback`: Type alias for streaming callbacks
|