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
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]
196 lines
7.8 KiB
Markdown
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
|