5e89f1016c
Move SubplanSpawnError from local subplan_service definition to centralized cleveragents.core.exceptions alongside four new spec-defined error types: SubplanExecutionError, MaxParallelExceededError, and SubplanDepthLimitError. Per the v3.3.0 specification (AUTO-ARCH-6), all subplan-related errors are defined in exceptions.py with proper inheritance hierarchy under DomainError/ PlanError/BusinessRuleViolation. The old local SpawnValidationError class has been replaced with SubplanSpawnError(PlanError) with a simplified constructor API (message string instead of validation_errors list). Updates: - exceptions.py: Added 4 subplan error classes + __all__ entries - subplan_service.py: Remove local SpawnValidationError, import SubplanSpawnError from exceptions - services/__init__.py: Update TYPE_CHECKING stub and _LAZY_IMPORTS for new location - vulture_whitelist.py: Replace old entry with new error class names - docs/reference/subplan_service.md: Update to reference SubplanSpawnError (v3.3.0) - features/*.feature + steps: Update test references from SpawnValidationError to SubplanSpawnError
142 lines
5.7 KiB
Markdown
142 lines
5.7 KiB
Markdown
# Subplan Service: Spawn Workflow and Lifecycle
|
|
|
|
The `SubplanService` coordinates the spawning of child plans from
|
|
`DecisionService` spawn entries and `SubplanConfig`. It validates
|
|
resource scopes, merge strategies, and parallelism bounds before
|
|
creating child plan statuses.
|
|
|
|
## Overview
|
|
|
|
When a parent plan decides to decompose work into child plans (via
|
|
`subplan_spawn` or `subplan_parallel_spawn` decisions during Strategize),
|
|
the `SubplanService` handles the spawn workflow:
|
|
|
|
1. Extract spawn decisions from the `DecisionService`
|
|
2. Build `SpawnEntry` objects from those decisions
|
|
3. Validate the spawn request
|
|
4. Create `SubplanStatus` and `SpawnMetadata` for each entry
|
|
5. Return the result for the caller to persist on the parent plan
|
|
|
|
## Spawn Workflow
|
|
|
|
```
|
|
DecisionService SubplanService Parent Plan
|
|
| | |
|
|
| get_spawn_decisions | |
|
|
|<-----------------------| |
|
|
| [Decision, ...] | |
|
|
|----------------------->| |
|
|
| | build_spawn_entries |
|
|
| | validate_spawn |
|
|
| | spawn |
|
|
| |------------------------->|
|
|
| | SpawnResult |
|
|
| | (statuses + metadata) |
|
|
```
|
|
|
|
## Key Types
|
|
|
|
### SpawnMetadata
|
|
|
|
Persisted alongside each child plan for status output and provenance:
|
|
|
|
| Field | Type | Description |
|
|
|---------------------|--------|------------------------------------------|
|
|
| `spawn_decision_id` | `str` | ULID of the decision that triggered spawn|
|
|
| `parent_plan_id` | `str` | ULID of the parent plan |
|
|
| `root_plan_id` | `str` | ULID of the root plan in the hierarchy |
|
|
| `execution_mode` | `str` | How the subplan should be executed |
|
|
|
|
### SpawnEntry
|
|
|
|
A single spawn request derived from a decision:
|
|
|
|
| Field | Type | Description |
|
|
|--------------------|--------------|--------------------------------------|
|
|
| `decision` | `Decision` | The decision that triggered spawn |
|
|
| `action_name` | `str` | Namespaced action name for child plan|
|
|
| `target_resources` | `list[str]` | Resource IDs the child plan uses |
|
|
| `description` | `str` | Description/prompt for the child plan|
|
|
|
|
### SpawnResult
|
|
|
|
Result of spawning child plans:
|
|
|
|
| Field | Type | Description |
|
|
|--------------------|-------------------------------|--------------------------------|
|
|
| `spawned_statuses` | `list[SubplanStatus]` | Status for each child plan |
|
|
| `metadata` | `dict[str, SpawnMetadata]` | Metadata keyed by subplan_id |
|
|
| `total_spawned` | `int` | Number of child plans created |
|
|
| `execution_mode` | `str` | Execution mode from config |
|
|
|
|
## Spawn Validation
|
|
|
|
Before any child plan is created, `validate_spawn` checks:
|
|
|
|
1. **Resource scopes resolved**: All `target_resources` in each entry
|
|
exist in the `available_resources` set. Unresolved resources produce
|
|
a validation error.
|
|
|
|
2. **Merge strategy defined**: The `SubplanConfig.merge_strategy` must
|
|
not be `None`. Without a merge strategy, child plan results cannot
|
|
be combined.
|
|
|
|
3. **max_parallel bounds**: In `PARALLEL` execution mode, the number of
|
|
spawn entries must not exceed `config.max_parallel`.
|
|
|
|
4. **Valid action names**: Each entry must have a non-empty `action_name`.
|
|
|
|
5. **Correct decision types**: Each entry's decision must be either
|
|
`subplan_spawn` or `subplan_parallel_spawn`.
|
|
|
|
If any check fails, `SubplanSpawnError` is raised with a message listing all errors.
|
|
|
|
## Integration with Other Services
|
|
|
|
- **DecisionService**: Provides spawn-type decisions via
|
|
`list_by_type(plan_id, "subplan_spawn")`.
|
|
- **SubplanExecutionService**: Executes the spawned child plans using
|
|
the `SubplanStatus` objects from `SpawnResult`.
|
|
- **SubplanMergeService**: Merges child plan outputs using the strategy
|
|
from `SubplanConfig`.
|
|
- **PlanLifecycleService**: Manages the parent plan's lifecycle,
|
|
persisting the updated `subplan_statuses` and `subplan_config`.
|
|
|
|
## Example Usage
|
|
|
|
```python
|
|
from cleveragents.application.services.subplan_service import (
|
|
SubplanService,
|
|
)
|
|
|
|
# Get spawn decisions for the parent plan
|
|
decisions = subplan_service.get_spawn_decisions(parent_plan.identity.plan_id)
|
|
|
|
# Build spawn entries from decisions
|
|
entries = subplan_service.build_spawn_entries(decisions)
|
|
|
|
# Spawn child plans (validates first)
|
|
result = subplan_service.spawn(
|
|
parent_plan=parent_plan,
|
|
config=parent_plan.subplan_config,
|
|
spawn_entries=entries,
|
|
available_resources=frozenset(known_resource_ids),
|
|
)
|
|
|
|
# Update the parent plan with spawned statuses
|
|
parent_plan.subplan_statuses = result.spawned_statuses
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
| Error | When |
|
|
|------------------------------|---------------------------------------------|
|
|
| `ValueError` | `None` or empty required arguments |
|
|
| `SubplanSpawnError` (v3.3.0) | Validation checks fail (resource scope, |
|
|
| | merge strategy, max_parallel, action name, |
|
|
| | or decision type) |
|
|
|
|
`SubplanSpawnError` inherits from `PlanError` and carries a descriptive message
|
|
listing all validation failures. The error is centralized in
|
|
`cleveragents.core.exceptions` (moved from the local subplan_service module in v3.3.0).
|