Files
cleveragents-core/features/plan_actor_integration.feature
freemo dfa05a6909
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 26s
CI / quality (pull_request) Successful in 32s
CI / build (pull_request) Successful in 35s
CI / security (pull_request) Successful in 52s
CI / typecheck (pull_request) Successful in 56s
CI / e2e_tests (pull_request) Successful in 1m36s
CI / unit_tests (pull_request) Successful in 3m25s
CI / integration_tests (pull_request) Successful in 3m55s
CI / docker (pull_request) Successful in 57s
CI / coverage (pull_request) Successful in 6m54s
CI / lint (push) Successful in 14s
CI / quality (push) Successful in 35s
CI / typecheck (push) Successful in 39s
CI / security (push) Successful in 51s
CI / benchmark-regression (push) Has been skipped
CI / build (push) Successful in 21s
CI / e2e_tests (push) Successful in 2m14s
CI / unit_tests (push) Successful in 5m9s
CI / integration_tests (push) Successful in 5m29s
CI / docker (push) Successful in 1m6s
CI / coverage (push) Successful in 6m12s
CI / benchmark-publish (push) Successful in 20m51s
CI / benchmark-regression (pull_request) Successful in 37m16s
fix(cli): wire real LLM actors into plan executor for production execution
The `plan execute` CLI command only performed phase transitions
(Strategize → Execute) without ever invoking the `PlanExecutor` to
drive the strategize or execute actors.  `PlanExecutor.__init__`
unconditionally created `StrategizeStubActor()` and
`ExecuteStubActor()` which parse text locally and return empty
changesets — no real LLM call was made.

Added `_get_plan_executor()` helper that resolves `ProviderRegistry`
from the DI container and constructs `LLMStrategizeActor` /
`LLMExecuteActor` for real LLM invocations via LangChain.  Updated
`execute_plan` CLI command to detect plan phase/state and
automatically run the appropriate actor:

- Strategize/queued  → run strategize actor → transition to Execute
- Strategize/complete → phase transition only (backward compat)
- Execute/queued     → run execute actor → mark complete

New `llm_actors.py` module provides `LLMStrategizeActor` (task
decomposition into numbered steps) and `LLMExecuteActor` (code
generation with FILE: blocks).  Both resolve `provider/model` actor
names (e.g. `openai/gpt-4`) to live LangChain LLM instances.

`PlanExecutor.__init__` now accepts optional `strategize_actor` and
`execute_actor` parameters, falling back to stubs when None.
Existing mock-based BDD tests remain backward-compatible via duck-
typing fallback (MagicMock.phase is not a PlanPhase, so the legacy
`service.execute_plan()` path is taken).

Includes Behave BDD scenarios testing custom actor injection into
PlanExecutor.

ISSUES CLOSED: #960
2026-03-15 19:59:38 -04:00

174 lines
7.2 KiB
Gherkin

Feature: Plan Actor Integration
As a developer
I want strategize and execute stub actors to drive plan phases
So that plans can be processed through the full lifecycle with ChangeSet capture
Background:
Given I have a plan executor service
# Strategize stub actor tests
Scenario: Strategize stub produces decisions from definition of done
Given I have a plan in strategize queued state with definition "Tests pass\nCoverage >= 90%"
When I run the strategize phase
Then strategize should produce 2 decisions
And the decision root id should be set on the plan
And the plan should be in strategize complete state
Scenario: Strategize stub handles single-line definition of done
Given I have a plan in strategize queued state with definition "All tests pass"
When I run the strategize phase
Then strategize should produce 1 decisions
And the decision root id should be set on the plan
Scenario: Strategize stub handles empty definition of done
Given I have a plan in strategize queued state with empty definition
When I run the strategize phase
Then strategize should produce 1 decisions
And the first decision should be "Complete the plan objectives"
Scenario: Strategize stub handles bullet list definition of done
Given I have a plan in strategize queued state with definition "- Unit tests pass\n- Integration tests pass\n- Coverage above threshold"
When I run the strategize phase
Then strategize should produce 3 decisions
Scenario: Strategize stub records invariant enforcement
Given I have a plan with invariants in strategize queued state
When I run the strategize phase
Then the strategize result should include invariant records
And each invariant record should have enforcement status
Scenario: Strategize is read-only and does not modify resources
Given I have a plan in strategize queued state with definition "Tests pass"
When I run the strategize phase
Then no changeset should be produced during strategize
And the plan sandbox refs should be empty
# Execute stub actor tests
Scenario: Execute stub captures tool calls through ChangeSet
Given I have a plan that completed strategize
When I run the execute phase
Then the changeset id should be set on the plan
And the plan should be in execute complete state
Scenario: Execute stub records execution metadata
Given I have a plan that completed strategize
When I run the execute phase
Then the plan should have execution metadata
And the tool calls count should be recorded
Scenario: Execute stub uses sandbox when provided
Given I have a plan executor with sandbox root
And I have a plan that completed strategize
When I run the execute phase
Then the plan sandbox refs should not be empty
# Phase transition guards
Scenario: Execute is prevented when plan is not in Strategize COMPLETE state
Given I have a plan in strategize queued state with definition "Tests pass"
When I try to run the execute phase
Then a plan error should be raised about phase mismatch
Scenario: Execute is prevented when plan has no decision tree
Given I have a plan in execute queued state without decisions
When I try to run the execute phase on the executor
Then a plan error should be raised about missing decisions
Scenario: Strategize fails when plan is not in strategize phase
Given I have a plan in execute phase for executor
When I try to run the strategize phase
Then a plan error should be raised about phase mismatch
# Error handling and status updates
Scenario: Strategize failure captures error details
Given I have a plan in strategize queued state with definition "Tests pass"
And the strategize actor is configured to fail
When I try to run the strategize phase expecting failure
Then the plan should be in errored state
And the plan should have error details
Scenario: Execute failure captures error details
Given I have a plan that completed strategize
And the execute actor is configured to fail
When I try to run the execute phase expecting failure
Then the plan should be in errored state
And the plan should have error details
# Streaming hooks
Scenario: Strategize emits streaming events
Given I have a plan in strategize queued state with definition "Tests pass"
And I have a stream callback registered
When I run the strategize phase with streaming
Then the stream callback should have received strategize events
And the stream events should include strategize_started
And the stream events should include strategize_complete
Scenario: Execute emits streaming events
Given I have a plan that completed strategize
And I have a stream callback registered
When I run the execute phase with streaming
Then the stream callback should have received execute events
And the stream events should include execute_started
And the stream events should include execute_complete
# Validation
Scenario: Strategize rejects empty plan id
When I try to run strategize with empty plan id
Then a validation error should be raised for empty plan id
Scenario: Execute rejects empty plan id
When I try to run execute with empty plan id
Then a validation error should be raised for empty plan id
Scenario: PlanExecutor rejects None lifecycle service
When I try to create a PlanExecutor with None lifecycle service
Then a validation error should be raised for None lifecycle service
# Strategy decision model
Scenario: StrategyDecision model validates fields
When I create a strategy decision with valid fields
Then the strategy decision should have the correct attributes
Scenario: StrategizeResult model stores decisions
When I create a strategize result with 3 decisions
Then the result should contain 3 decisions
And the result should have a root id
Scenario: ExecuteResult model stores changeset
When I create an execute result with changeset
Then the result should have a changeset id
And the result should have a changeset object
# Full lifecycle integration
Scenario: Full strategize then execute lifecycle
Given I have a plan in strategize queued state with definition "Write tests\nRun linter\nVerify coverage"
When I run the strategize phase
And I transition the plan to execute
And I run the execute phase
Then the plan should be in execute complete state
And the changeset id should be set on the plan
And the decision root id should be set on the plan
# PlanExecutor with injected actors
Scenario: PlanExecutor accepts custom strategize actor
Given I have a plan executor with a custom strategize actor
And I have a plan in strategize queued state with definition "Custom task"
When I run the strategize phase
Then the custom strategize actor should have been called
And the plan should be in strategize complete state
Scenario: PlanExecutor accepts custom execute actor
Given I have a plan executor with a custom execute actor
And I have a plan that completed strategize
When I run the execute phase
Then the custom execute actor should have been called
And the plan should be in execute complete state