forked from cleveragents/cleveragents-core
120274da99
Create DecisionService application-layer service that wraps DecisionRepository with structured logging and UnitOfWork transaction management. Wire DecisionService and PlanLifecycleService into the DI container as Factory providers. Inject DecisionService into PlanLifecycleService so that phase transitions automatically record decisions: start_strategize records a strategy_choice decision and start_execute records an implementation_choice decision. Decision recording is optional and never blocks lifecycle transitions. Add Behave feature (5 scenarios), Robot Framework smoke tests (2 test cases), ASV benchmarks (3 benchmark classes), and DI reference documentation. ISSUES CLOSED: #173
4.4 KiB
4.4 KiB
Dependency Injection Reference
The CleverAgents DI container is built on dependency-injector's
DeclarativeContainer. All service registrations live in
src/cleveragents/application/container.py.
Container Overview
| Provider | Type | Description |
|---|---|---|
settings |
Singleton | Application settings |
provider_registry |
Singleton | AI provider registry |
database_url |
Callable | Database URL resolution |
unit_of_work |
Factory | Unit of Work (new per request) |
ai_provider |
Singleton | AI provider instance |
project_service |
Factory | Project management service |
vector_store_service |
Factory | Vector store operations |
context_service |
Factory | Context management service |
actor_service |
Factory | Actor configuration service |
actor_registry |
Factory | Actor registry with provider binding |
plan_service |
Factory | Legacy plan management (deprecated) |
decision_service |
Factory | Decision tree recording service |
plan_lifecycle_service |
Factory | V3 four-phase plan lifecycle |
resource_registry_service |
Factory | Resource registry operations |
namespaced_project_repo |
Factory | Namespaced project repository |
project_resource_link_repo |
Factory | Project-resource link repository |
stream_router |
Singleton | Reactive stream routing |
langgraph_bridge |
Singleton | LangGraph integration bridge |
route_bridge |
Singleton | Reactive route bridge |
Decision Service Registration
The DecisionService is registered as a Factory provider, meaning
each resolution returns a new instance. It depends on:
settings— Application settings (Singleton)unit_of_work— Unit of Work (Factory)
decision_service = providers.Factory(
DecisionService,
settings=settings,
unit_of_work=unit_of_work,
)
DecisionService wraps DecisionRepository (accessible via
UnitOfWorkContext.decisions) and provides:
| Method | Description |
|---|---|
record_decision() |
Persist a new decision |
get_decision() |
Retrieve a decision by ID |
get_decisions_for_plan() |
Get all decisions for a plan |
get_decision_tree() |
BFS traversal of the decision tree |
get_path_to_root() |
Walk from a decision up to the root |
mark_superseded() |
Mark a decision as superseded |
list_by_type() |
List decisions by type for a plan |
Plan Lifecycle Service Registration
The PlanLifecycleService is registered as a Factory provider
with the DecisionService injected:
plan_lifecycle_service = providers.Factory(
PlanLifecycleService,
settings=settings,
unit_of_work=unit_of_work,
decision_service=decision_service,
)
When a DecisionService is wired, the lifecycle service automatically
records decisions during phase transitions:
- start_strategize → records a
strategy_choicedecision - start_execute → records an
implementation_choicedecision
If no DecisionService is provided (e.g. in legacy tests), decision
recording is silently skipped.
Usage Example
from cleveragents.application.container import get_container
container = get_container()
# Resolve services
decision_svc = container.decision_service()
lifecycle_svc = container.plan_lifecycle_service()
# Record a decision manually
from cleveragents.domain.models.core.decision import Decision, DecisionType
decision = Decision(
plan_id="01HV...",
sequence_number=0,
decision_type=DecisionType.STRATEGY_CHOICE,
question="Which approach?",
chosen_option="Approach A",
)
decision_svc.record_decision(decision)
# Retrieve decisions
decisions = decision_svc.get_decisions_for_plan("01HV...")