docs: add API documentation (CLI reference, Python API, protocols) [AUTO-DOCS-2]
CI / push-validation (pull_request) Successful in 16s
CI / build (pull_request) Successful in 24s
CI / helm (pull_request) Successful in 28s
CI / quality (pull_request) Successful in 32s
CI / lint (pull_request) Successful in 34s
CI / typecheck (pull_request) Successful in 48s
CI / security (pull_request) Successful in 59s
CI / e2e_tests (pull_request) Successful in 3m3s
CI / integration_tests (pull_request) Successful in 3m54s
CI / unit_tests (pull_request) Successful in 5m0s
CI / docker (pull_request) Successful in 11s
CI / coverage (pull_request) Successful in 10m50s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 57m42s
CI / push-validation (pull_request) Successful in 16s
CI / build (pull_request) Successful in 24s
CI / helm (pull_request) Successful in 28s
CI / quality (pull_request) Successful in 32s
CI / lint (pull_request) Successful in 34s
CI / typecheck (pull_request) Successful in 48s
CI / security (pull_request) Successful in 59s
CI / e2e_tests (pull_request) Successful in 3m3s
CI / integration_tests (pull_request) Successful in 3m54s
CI / unit_tests (pull_request) Successful in 5m0s
CI / docker (pull_request) Successful in 11s
CI / coverage (pull_request) Successful in 10m50s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 57m42s
This commit is contained in:
@@ -0,0 +1,525 @@
|
||||
# Python API — Application Layer
|
||||
|
||||
This page documents the **application layer** of the CleverAgents Python package:
|
||||
application services, the dependency injection (DI) container, domain models,
|
||||
and key protocols. For module-level API documentation (exceptions, registries,
|
||||
adapters) see the [Module Index](index.md).
|
||||
|
||||
See [ADR-001](../adr/ADR-001-layered-architecture.md) (layered architecture) and
|
||||
[ADR-003](../adr/ADR-003-dependency-injection.md) (dependency injection) for
|
||||
design rationale.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
CleverAgents follows a strict layered architecture:
|
||||
|
||||
```
|
||||
Entry Points (CLI / TUI / A2A server)
|
||||
↓
|
||||
Application Layer ← this page
|
||||
↓
|
||||
Domain Layer (models, value objects, domain services)
|
||||
↓
|
||||
Infrastructure (database, file system, external services)
|
||||
↓
|
||||
Integration (LangChain/LangGraph, MCP, LSP adapters)
|
||||
↓
|
||||
Core (exceptions, retry, circuit breaker, async cleanup)
|
||||
```
|
||||
|
||||
All cross-layer dependencies flow **downward only**. The DI container wires
|
||||
everything together at startup.
|
||||
|
||||
---
|
||||
|
||||
## Dependency Injection Container
|
||||
|
||||
**Module:** `cleveragents.application.container`
|
||||
|
||||
CleverAgents uses [dependency-injector](https://python-dependency-injector.ets-labs.org/)
|
||||
for IoC. The `CleverAgentsContainer` is the root container; all application
|
||||
services are registered as providers and resolved lazily.
|
||||
|
||||
```python
|
||||
from cleveragents.application.container import CleverAgentsContainer
|
||||
|
||||
container = CleverAgentsContainer()
|
||||
container.config.from_dict({"provider": "openai", ...})
|
||||
container.wire(modules=[__name__])
|
||||
|
||||
# Resolve services
|
||||
plan_service = container.plan_service()
|
||||
registry_service = container.registry_service()
|
||||
session_service = container.session_service()
|
||||
invariant_service = container.invariant_service()
|
||||
```
|
||||
|
||||
### Key Providers
|
||||
|
||||
| Provider | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `container.settings` | `Singleton` | Application `Settings` instance |
|
||||
| `container.event_bus` | `Singleton` | In-process event bus |
|
||||
| `container.plan_service` | `Singleton` | `PlanLifecycleService` |
|
||||
| `container.registry_service` | `Singleton` | `RegistryService` |
|
||||
| `container.session_service` | `Singleton` | `SessionService` |
|
||||
| `container.invariant_service` | `Singleton` | `InvariantService` |
|
||||
| `container.actor_registry` | `Singleton` | `ActorRegistry` |
|
||||
| `container.tool_registry` | `Singleton` | `ToolRegistry` |
|
||||
| `container.skill_registry` | `Singleton` | `SkillRegistry` |
|
||||
| `container.provider_registry` | `Singleton` | `ProviderRegistry` |
|
||||
| `container.mcp_registry` | `Singleton` | `McpRegistry` |
|
||||
| `container.lsp_registry` | `Singleton` | `LSPRegistry` |
|
||||
| `container.resource_registry` | `Singleton` | `ResourceRegistry` |
|
||||
| `container.a2a_facade` | `Singleton` | `A2aLocalFacade` |
|
||||
|
||||
> **Tip:** Always obtain services via the container rather than constructing
|
||||
> them directly. This ensures correct lifecycle management and dependency
|
||||
> resolution.
|
||||
|
||||
---
|
||||
|
||||
## PlanLifecycleService
|
||||
|
||||
**Module:** `cleveragents.application.services.plan_service`
|
||||
|
||||
The central application service for the plan lifecycle. Orchestrates the
|
||||
four phases (Action → Strategize → Execute → Apply) and coordinates actors,
|
||||
tools, resources, and invariants.
|
||||
|
||||
```python
|
||||
from cleveragents.application.services.plan_service import PlanLifecycleService
|
||||
|
||||
service: PlanLifecycleService = container.plan_service()
|
||||
|
||||
# Create a plan from an action
|
||||
plan = await service.create_plan(
|
||||
action_name="local/refactor",
|
||||
project_names=["my-project"],
|
||||
args={"target": "src/"},
|
||||
automation_profile="review",
|
||||
)
|
||||
|
||||
# Execute the plan (Strategize + Execute phases)
|
||||
result = await service.execute_plan(plan.plan_id)
|
||||
|
||||
# Apply the sandbox changeset
|
||||
await service.apply_plan(plan.plan_id)
|
||||
```
|
||||
|
||||
### Key Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `create_plan(action_name, project_names, args, ...)` | `Plan` | Instantiate a plan from an action |
|
||||
| `execute_plan(plan_id)` | `PlanExecutionResult` | Run Strategize and Execute phases |
|
||||
| `apply_plan(plan_id)` | `PlanApplyResult` | Merge sandbox changeset into real resources |
|
||||
| `get_plan(plan_id)` | `Plan` | Retrieve a plan by ID |
|
||||
| `list_plans(filters)` | `list[Plan]` | List plans with optional filters |
|
||||
| `cancel_plan(plan_id, reason)` | `Plan` | Cancel a running plan |
|
||||
| `rollback_plan(plan_id, checkpoint_id)` | `Plan` | Roll back to a checkpoint |
|
||||
| `get_plan_diff(plan_id)` | `PlanDiff` | Get the sandbox diff for a plan |
|
||||
| `correct_decision(decision_id, mode, guidance)` | `CorrectionAttempt` | Correct a decision and recompute |
|
||||
| `get_decision_tree(plan_id)` | `DecisionTree` | Retrieve the full decision tree |
|
||||
|
||||
---
|
||||
|
||||
## RegistryService
|
||||
|
||||
**Module:** `cleveragents.application.services.registry_service`
|
||||
|
||||
Unified CRUD service for all registry entities: actions, actors, skills,
|
||||
tools, resources, projects, LSP servers, and automation profiles.
|
||||
|
||||
```python
|
||||
from cleveragents.application.services.registry_service import RegistryService
|
||||
|
||||
service: RegistryService = container.registry_service()
|
||||
|
||||
# Register an action from a YAML file
|
||||
action = await service.register_action(Path("examples/actions/refactor.yaml"))
|
||||
|
||||
# List all tools
|
||||
tools = await service.list_tools(namespace="local", source="mcp")
|
||||
|
||||
# Register a resource
|
||||
resource = await service.register_resource(
|
||||
type_name="git-checkout",
|
||||
name="local/my-repo",
|
||||
args={"url": "https://github.com/org/repo.git"},
|
||||
)
|
||||
```
|
||||
|
||||
### Key Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `register_action(path, update=False)` | Register or update an action from YAML |
|
||||
| `list_actions(namespace, state, regex)` | List actions |
|
||||
| `get_action(name)` | Get an action by name |
|
||||
| `archive_action(name)` | Archive an action |
|
||||
| `register_actor(path, update=False)` | Register or update an actor from YAML |
|
||||
| `list_actors()` | List all actors |
|
||||
| `get_actor(name)` | Get an actor by name |
|
||||
| `register_skill(path, update=False)` | Register or update a skill from YAML |
|
||||
| `list_skills(namespace, source)` | List skills |
|
||||
| `register_tool(path, update=False)` | Register or update a tool from YAML |
|
||||
| `list_tools(namespace, source, type)` | List tools |
|
||||
| `register_resource(type_name, name, args)` | Register a resource |
|
||||
| `list_resources(type, include_stopped)` | List resources |
|
||||
| `get_resource(name)` | Get a resource by name |
|
||||
| `create_project(name, description, resources, invariants)` | Create a project |
|
||||
| `list_projects(namespace, regex)` | List projects |
|
||||
| `link_resource_to_project(project, resource, read_only)` | Link a resource to a project |
|
||||
|
||||
---
|
||||
|
||||
## SessionService
|
||||
|
||||
**Module:** `cleveragents.application.services.session_service`
|
||||
|
||||
Manages conversation sessions — creation, retrieval, message history,
|
||||
export, and import.
|
||||
|
||||
```python
|
||||
from cleveragents.application.services.session_service import SessionService
|
||||
|
||||
service: SessionService = container.session_service()
|
||||
|
||||
# Create a session
|
||||
session = await service.create_session(actor="openai/gpt-4o")
|
||||
|
||||
# Send a message
|
||||
response = await service.send_message(
|
||||
session_id=session.session_id,
|
||||
content="What is the current plan status?",
|
||||
)
|
||||
|
||||
# Export as JSON
|
||||
export_data = await service.export_session(session.session_id)
|
||||
|
||||
# Export as Markdown transcript
|
||||
md = await service.export_session_markdown(session.session_id)
|
||||
```
|
||||
|
||||
### Key Methods
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `create_session(actor)` | Create a new session |
|
||||
| `get_session(session_id)` | Retrieve a session |
|
||||
| `list_sessions()` | List all sessions |
|
||||
| `delete_session(session_id)` | Delete a session |
|
||||
| `send_message(session_id, content, stream)` | Send a message and get a response |
|
||||
| `export_session(session_id)` | Export session as a JSON-serializable dict |
|
||||
| `export_session_markdown(session_id)` | Export session as a Markdown transcript |
|
||||
| `import_session(data)` | Import a session from a previously exported dict |
|
||||
|
||||
---
|
||||
|
||||
## InvariantService
|
||||
|
||||
**Module:** `cleveragents.application.services.invariant_service`
|
||||
|
||||
See [`cleveragents.core` — Invariant Service](core.md#invariant-service) for
|
||||
the full API reference. The service is registered as a Singleton in the DI
|
||||
container:
|
||||
|
||||
```python
|
||||
invariant_service = container.invariant_service()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Domain Models
|
||||
|
||||
**Module:** `cleveragents.domain.models`
|
||||
|
||||
All domain models inherit from `DomainBaseModel` (see [Core Utilities](core.md#domain-base-model)).
|
||||
|
||||
### Plan
|
||||
|
||||
```python
|
||||
from cleveragents.domain.models.core.plan import Plan, PlanPhase, PlanState
|
||||
|
||||
class Plan(DomainBaseModel):
|
||||
plan_id: str # ULID
|
||||
name: str | None # namespaced name (top-level plans only)
|
||||
action_name: str # action this plan was instantiated from
|
||||
project_names: list[str] # bound projects
|
||||
phase: PlanPhase # Action | Strategize | Execute | Apply
|
||||
state: PlanState # running | applied | errored | cancelled | ...
|
||||
automation_profile: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
parent_plan_id: str | None
|
||||
```
|
||||
|
||||
**`PlanPhase`** enum: `ACTION`, `STRATEGIZE`, `EXECUTE`, `APPLY`
|
||||
|
||||
**`PlanState`** enum: `RUNNING`, `APPLIED`, `CONSTRAINED`, `ERRORED`, `CANCELLED`
|
||||
|
||||
### Action
|
||||
|
||||
```python
|
||||
from cleveragents.domain.models.core.action import Action
|
||||
|
||||
class Action(DomainBaseModel):
|
||||
name: str # namespaced name
|
||||
description: str
|
||||
definition_of_done: str
|
||||
strategy_actor: str | None
|
||||
execution_actor: str | None
|
||||
estimation_actor: str | None
|
||||
invariant_actor: str | None
|
||||
args: list[ActionArgument]
|
||||
invariants: list[str]
|
||||
state: str # "active" | "archived"
|
||||
```
|
||||
|
||||
### Decision
|
||||
|
||||
```python
|
||||
from cleveragents.domain.models.core.decision import Decision, DecisionType
|
||||
|
||||
class Decision(DomainBaseModel):
|
||||
decision_id: str # ULID
|
||||
plan_id: str
|
||||
type: DecisionType
|
||||
question: str
|
||||
chosen_option: str
|
||||
alternatives: list[str]
|
||||
confidence: float # 0.0–1.0
|
||||
rationale: str
|
||||
phase: PlanPhase
|
||||
created_at: datetime
|
||||
superseded_by: str | None
|
||||
```
|
||||
|
||||
**`DecisionType`** enum: `PROMPT_DEFINITION`, `INVARIANT_ENFORCED`,
|
||||
`STRATEGY_CHOICE`, `SUBPLAN_SPAWN`, `SUBPLAN_PARALLEL_SPAWN`, …
|
||||
|
||||
### Resource
|
||||
|
||||
```python
|
||||
from cleveragents.domain.models.core.resource import Resource
|
||||
|
||||
class Resource(DomainBaseModel):
|
||||
resource_id: str # ULID
|
||||
name: str # namespaced name
|
||||
type_name: str # e.g. "git-checkout", "sqlite"
|
||||
description: str | None
|
||||
is_physical: bool
|
||||
parent_ids: list[str]
|
||||
child_ids: list[str]
|
||||
state: str # "active" | "stopped"
|
||||
created_at: datetime
|
||||
```
|
||||
|
||||
### Project
|
||||
|
||||
```python
|
||||
from cleveragents.domain.models.core.project import Project
|
||||
|
||||
class Project(DomainBaseModel):
|
||||
name: str # namespaced name (sole identifier — no ULID)
|
||||
description: str | None
|
||||
resource_links: list[ResourceLink]
|
||||
invariants: list[str]
|
||||
context_policy: ContextPolicy | None
|
||||
created_at: datetime
|
||||
```
|
||||
|
||||
### Session
|
||||
|
||||
```python
|
||||
from cleveragents.domain.models.core.session import Session
|
||||
|
||||
class Session(DomainBaseModel):
|
||||
session_id: str
|
||||
actor: str
|
||||
messages: list[Message]
|
||||
linked_plan_ids: list[str]
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
def as_export_markdown(self) -> str:
|
||||
"""Render a human-readable Markdown transcript (lossy, not importable)."""
|
||||
```
|
||||
|
||||
### Invariant
|
||||
|
||||
```python
|
||||
from cleveragents.domain.models.core.invariant import Invariant, InvariantScope
|
||||
|
||||
class Invariant(DomainBaseModel):
|
||||
invariant_id: str # ULID
|
||||
text: str
|
||||
scope: InvariantScope # GLOBAL | PROJECT | ACTION | PLAN
|
||||
source_name: str # project/action/plan name, or "global"
|
||||
active: bool
|
||||
non_overridable: bool # global invariants only
|
||||
created_at: datetime
|
||||
```
|
||||
|
||||
**`InvariantScope`** enum: `GLOBAL`, `PROJECT`, `ACTION`, `PLAN`
|
||||
|
||||
---
|
||||
|
||||
## Key Protocols and Interfaces
|
||||
|
||||
### `AIProviderInterface`
|
||||
|
||||
**Module:** `cleveragents.providers.interface`
|
||||
|
||||
Protocol that all AI provider implementations must satisfy.
|
||||
|
||||
```python
|
||||
class AIProviderInterface(Protocol):
|
||||
@property
|
||||
def name(self) -> str: ...
|
||||
|
||||
@property
|
||||
def model_id(self) -> str: ...
|
||||
|
||||
async def generate(
|
||||
self,
|
||||
messages: list[Message],
|
||||
tools: list[ToolSpec] | None = None,
|
||||
stream: bool = False,
|
||||
) -> GenerationResult: ...
|
||||
```
|
||||
|
||||
### `ResourceHandler`
|
||||
|
||||
**Module:** `cleveragents.resource.handlers.base`
|
||||
|
||||
Protocol for resource handler implementations.
|
||||
|
||||
```python
|
||||
class ResourceHandler(Protocol):
|
||||
async def read(self, resource_id: str, context: ...) -> Any: ...
|
||||
async def write(self, resource_id: str, data: Any, context: ...) -> None: ...
|
||||
async def delete(self, resource_id: str, context: ...) -> None: ...
|
||||
async def list_children(self, resource_id: str, context: ...) -> list[str]: ...
|
||||
async def diff(self, resource_id: str, other_id: str, context: ...) -> str: ...
|
||||
async def checkpoint(self, resource_id: str) -> str: ...
|
||||
async def rollback(self, resource_id: str, checkpoint_id: str) -> None: ...
|
||||
async def create_sandbox(self, resource_id: str) -> "Sandbox": ...
|
||||
```
|
||||
|
||||
### `LLMCaller`
|
||||
|
||||
**Module:** `cleveragents.tool`
|
||||
|
||||
Protocol for calling an LLM. Implement this to plug in a custom provider
|
||||
into the tool-calling runtime.
|
||||
|
||||
```python
|
||||
class LLMCaller(Protocol):
|
||||
async def call(
|
||||
self,
|
||||
messages: list[Message],
|
||||
tools: list[ToolSpec],
|
||||
) -> LLMResponse: ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## End-to-End Example
|
||||
|
||||
The following example shows how to use the Python API to create and execute
|
||||
a plan programmatically:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from cleveragents.application.container import CleverAgentsContainer
|
||||
|
||||
async def main():
|
||||
# Bootstrap the container
|
||||
container = CleverAgentsContainer()
|
||||
container.config.from_env("CLEVERAGENTS_")
|
||||
|
||||
plan_service = container.plan_service()
|
||||
registry_service = container.registry_service()
|
||||
|
||||
# Register a resource
|
||||
await registry_service.register_resource(
|
||||
type_name="git-checkout",
|
||||
name="local/my-repo",
|
||||
args={"url": "https://github.com/org/repo.git", "path": "/workspace/repo"},
|
||||
)
|
||||
|
||||
# Create a project
|
||||
await registry_service.create_project(
|
||||
name="my-project",
|
||||
description="Main application project",
|
||||
resources=["local/my-repo"],
|
||||
)
|
||||
|
||||
# Instantiate a plan
|
||||
plan = await plan_service.create_plan(
|
||||
action_name="local/refactor",
|
||||
project_names=["my-project"],
|
||||
args={"target": "src/"},
|
||||
automation_profile="review",
|
||||
)
|
||||
print(f"Plan created: {plan.plan_id}")
|
||||
|
||||
# Execute the plan
|
||||
result = await plan_service.execute_plan(plan.plan_id)
|
||||
print(f"Execution result: {result.state}")
|
||||
|
||||
# Review the decision tree
|
||||
tree = await plan_service.get_decision_tree(plan.plan_id)
|
||||
for decision in tree.decisions:
|
||||
print(f" [{decision.type}] {decision.question[:60]}…")
|
||||
|
||||
# Apply if satisfied
|
||||
await plan_service.apply_plan(plan.plan_id)
|
||||
print("Plan applied successfully.")
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Event Bus
|
||||
|
||||
**Module:** `cleveragents.application.events`
|
||||
|
||||
The in-process event bus enables loose coupling between application services.
|
||||
Services emit events; subscribers react without direct dependencies.
|
||||
|
||||
```python
|
||||
from cleveragents.application.events import EventBus, EventType
|
||||
|
||||
bus: EventBus = container.event_bus()
|
||||
|
||||
# Subscribe to plan phase transitions
|
||||
@bus.on(EventType.PLAN_PHASE_CHANGED)
|
||||
async def on_phase_change(event):
|
||||
print(f"Plan {event.plan_id} moved to {event.new_phase}")
|
||||
|
||||
# Emit an event (done internally by services)
|
||||
await bus.emit(EventType.PLAN_PHASE_CHANGED, plan_id="01JXYZ...", new_phase="execute")
|
||||
```
|
||||
|
||||
### Key Event Types
|
||||
|
||||
| Event | Description |
|
||||
|-------|-------------|
|
||||
| `PLAN_CREATED` | A new plan was instantiated |
|
||||
| `PLAN_PHASE_CHANGED` | A plan advanced to a new phase |
|
||||
| `PLAN_APPLIED` | A plan was successfully applied |
|
||||
| `PLAN_CANCELLED` | A plan was cancelled |
|
||||
| `PLAN_ERRORED` | A plan encountered an unrecoverable error |
|
||||
| `DECISION_RECORDED` | A new decision was added to the decision tree |
|
||||
| `INVARIANT_VIOLATED` | An invariant was not satisfied |
|
||||
| `INVARIANT_ENFORCED` | An invariant enforcement record was created |
|
||||
| `INVARIANT_RECONCILED` | Invariant reconciliation completed for a phase |
|
||||
| `TOOL_EXECUTED` | A tool invocation completed |
|
||||
| `SESSION_CREATED` | A new session was created |
|
||||
| `SESSION_MESSAGE_ADDED` | A message was added to a session |
|
||||
Reference in New Issue
Block a user