Boundary fix: - Delete src/cleveractors/acms/index.py (ACMSIndex, FileTraversalEngine, IndexEntry, FileType, TierLevel) — these are CLI/storage concerns that belong in cleveragents-core per ADR-001; the file already exists there at cleveragents/acms/index.py - Clean src/cleveractors/acms/__init__.py: remove all index.py imports and re-exports; __all__ now derives purely from uko.__all__ ProviderRegistryPort (ADR-005): - Add src/cleveractors/ports/provider_registry.py: ProviderRegistryPort Protocol with get(provider, model) -> Agent | None; structural typing, no host imports, mirrors the shape of ToolRegistryPort - Update src/cleveractors/ports/__init__.py: export ProviderRegistryPort alongside ToolRegistryPort; update module docstring Wire provider resolution into the node executor: - compiler.py: _map_node now accepts actor_provider/actor_model defaults and merges them into AGENT node metadata (setdefault so per-node config values still win); compile_actor passes config.provider/config.model - nodes.py: Node.__init__ gains optional provider_registry parameter; _execute_agent resolution order is now: (1) pre-resolved agents dict, (2) ProviderRegistryPort.get(provider, model) from node metadata, (3) graceful synthetic fallback — the ValueError guard for missing config.agent is removed since the registry is a valid alternative path Documentation: - Port ADR-003 (actor abstraction definition) from cleveragents-core ADR-031 - Port ADR-004 (Jinja2 YAML template preprocessing) from cleveragents-core ADR-032 - Add ADR-005 (Provider Registry Protocol) for the new provider_registry port - Port five reference docs: actors_schema.md, actor_compiler.md, actor_config.md, actor_hierarchy.md, actors_examples.md - Port API reference: api/actor.md - Add provider field to all YAML examples in actors_examples.md, actor_hierarchy.md, and actor_config.md - Update error messages in actor_config.md to match actual validator output - Add graph-level provider/model propagation docs to actor_compiler.md - Add ADR-005 cross-references to ADR-001, ADR-002, and actors_schema.md - Fix ADR-005 status section to reflect that implementation is in this PR - Fix ADR-004 to reference actual test files (smoke.feature, not phantom ones) - Remove fabricated reserved-namespace constraint from ADR-003 Constraints - Fix broken LICENSE link in docs/index.md for MkDocs rendering - Add provider field to ActorConfigSchema table in api/actor.md - Add internal modules section to docs/specification.md (ticket item 7) - Fix markdown formatting in actors_schema.md provider field definition - Add ADR-005 cross-reference to actors_schema.md provider field section BDD coverage (7 scenarios, 30 steps): - ProviderRegistryPort happy-path resolution - Graceful fallback when provider registry returns None - Graceful fallback when no provider registry is supplied - Pre-resolved agents dict takes precedence over provider registry - Compile a minimal graph actor, reject missing provider, render template Post-review fixes applied in amend: - actors_examples.md and actor_hierarchy.md: added provider to all examples - ADR-003: removed fabricated reserved-namespace constraint - ADR-004: corrected phantom test file references - ADR-005: updated status to reflect implementation is included - Added 'no registry' and 'agents dict precedence' BDD scenarios - Added provider to api/actor.md ActorConfigSchema fields table - ADR-001 and ADR-002: added ADR-005 cross-references - actor_config.md: fixed error message to match validator - actor_compiler.md: documented graph-level provider/model propagation - index.md: fixed broken LICENSE link - actors_schema.md: added ADR-005 cross-reference ISSUES CLOSED: #4
7.9 KiB
cleveractors.actor — Actor System
The actor package provides the actor YAML configuration schema, loader,
and compiler. Actors are the primary units parsed and compiled by this
library — they encapsulate an LLM reference, a set of tool declarations,
and a LangGraph execution graph.
See ADR-003 for the actor abstraction definition and ADR-001 for the library boundary decisions.
!!! note "Lazy imports"
The actor package uses lazy imports to avoid pulling in heavy
transitive dependencies (LangChain, LangSmith) when only lightweight
submodules such as role_validation or schema are needed.
ActorConfigSchema
from cleveractors.actor.schema import ActorConfigSchema
Pydantic model representing a fully-parsed actor YAML file. Key fields:
| Field | Type | Description |
|---|---|---|
name |
str |
Actor identifier in namespace/name format |
type |
ActorType |
llm, tool, or graph |
description |
str |
Human-readable description |
version |
str |
Schema version (default "1.0") |
provider |
str | None |
LLM provider identifier (required for llm/graph; see ADR-005) |
model |
str | None |
LLM model identifier (required for llm/graph) |
system_prompt |
str | None |
System prompt; may contain Jinja2 templates |
tools |
list |
Tool references and inline tool definitions |
route |
RouteDefinition | None |
Graph topology (required for graph) |
memory |
MemoryConfig | None |
Conversation memory settings |
context |
ContextConfigSchema | None |
File inclusion settings |
context_view |
ContextView | None |
Role-based context filtering hint |
skills |
list[str] |
Skill references for capability acquisition |
lsp |
... | None |
Actor-level LSP server bindings |
See Actor YAML Schema for the full field reference.
ActorConfiguration
from cleveractors.actor.config import ActorConfiguration
Pydantic model representing a fully-parsed actor YAML file with compiled
graph configuration. Used internally by the compiler; surface-level
consumers typically work with ActorConfigSchema and CompiledActor.
| Field | Type | Description |
|---|---|---|
name |
str |
Actor identifier (namespaced) |
entry_node |
str |
Graph entry node name |
nodes |
dict[str, NodeConfig] |
Node definitions |
edges |
list[Edge] |
Graph edges |
lsp_binding |
LspBinding | None |
Per-node LSP server binding |
tool_sources |
list[str] |
Tool source references |
ActorLoader
from cleveractors.actor.loader import ActorLoader
from pathlib import Path
loader = ActorLoader(
search_roots=[Path("./actors/")],
tool_registry=my_tool_registry, # optional: ToolRegistryPort
)
configs = loader.discover()
Discovers and loads actor YAML files from a directory tree. Validates
graph reachability (all nodes reachable from entry_node) and reports
YAML line/column positions on error.
The optional tool_registry parameter accepts any object satisfying
ToolRegistryPort. Unknown
tool references produce warnings rather than errors, so the loader
degrades gracefully when running without a fully populated tool registry.
Methods
| Method | Description |
|---|---|
discover() |
Scan all search_roots for actor YAML files; returns list[ActorConfigSchema] |
load(path) |
Load and validate a single actor YAML file |
validate(config) |
Validate an ActorConfigSchema without loading from disk |
compile_actor / CompiledActor
from cleveractors.actor.compiler import compile_actor, CompiledActor
compiled: CompiledActor = compile_actor(config)
# or, with subgraph cycle detection:
compiled = compile_actor(config, actor_resolver=my_registry.get)
Compiles an ActorConfigSchema into a CompiledActor by validating the
graph, mapping nodes and edges to LangGraph data classes, and extracting
LSP bindings. See Actor Compiler for the
full pipeline description.
Parameters:
config—ActorConfigSchema(must beActorType.GRAPH)actor_resolver— Optional(name: str) -> ActorConfigSchema | Nonefor cross-actor subgraph cycle detection
Returns: CompiledActor
CompiledActor
| Field | Type | Description |
|---|---|---|
name |
str |
Actor name |
nodes |
dict[str, NodeConfig] |
LangGraph node configs |
edges |
list[Edge] |
LangGraph edges |
entry_point |
str |
Entry node ID |
metadata |
CompilationMetadata |
Diagnostic metadata |
CompilationMetadata
| Field | Type | Description |
|---|---|---|
node_ids |
list[str] |
All node IDs (sorted) |
tool_nodes |
list[str] |
Tool-type node IDs |
lsp_bindings |
list[LspBinding] |
Per-node LSP bindings |
subgraph_refs |
dict[str, str] |
Subgraph node → actor name |
entry_node |
str |
Entry point node ID |
exit_nodes |
list[str] |
Exit point node IDs |
Compilation Errors
from cleveractors.actor import (
ActorCompilationError,
MissingNodeError,
InvalidEntryExitError,
SubgraphCycleError,
)
| Exception | Description |
|---|---|
ActorCompilationError |
General compilation failure (base class) |
MissingNodeError |
Edge or entry/exit references a node not in the graph |
InvalidEntryExitError |
Entry or exit node configuration is invalid |
SubgraphCycleError |
Cycle detected within the graph or across subgraph references |
Extension Points (Ports)
from cleveractors.ports import ToolRegistryPort, ProviderRegistryPort
| Protocol | Used by | Purpose |
|---|---|---|
ToolRegistryPort |
ActorLoader |
Verify tool references at load time |
ProviderRegistryPort |
Node._execute_agent() |
Resolve (provider, model) to an Agent instance at execution time |
See ADR-002 and ADR-005 for the design rationale behind each port.
Supporting Types
LspBinding
from cleveractors.lsp.models import LspBinding
Data class describing an LSP server binding extracted during compilation. Consumed by the host application to start the appropriate language server.
VocabularyRegistry
from cleveractors.acms.uko import VocabularyRegistry
Registry of UKO (Universal Knowledge Ontology) vocabulary data used for context enrichment. Pure data; no I/O.
Agent
from cleveractors.agents.base import Agent
Minimal abstract base class for LLM-backed agents. Host applications
subclass Agent to wrap their concrete LangChain model instances and
return them from ProviderRegistryPort.get().
Error Types
from cleveractors.core import ValidationError, NotFoundError
| Exception | Description |
|---|---|
ValidationError |
Schema or semantic validation failure |
NotFoundError |
A named resource (actor, tool, skill) could not be found |
Example: Loading and Compiling an Actor
from pathlib import Path
from cleveractors.actor.loader import ActorLoader
from cleveractors.actor.compiler import compile_actor
from cleveractors.ports import ToolRegistryPort
# Provide a tool registry (any object with .get(name) -> spec | None)
loader = ActorLoader(
search_roots=[Path("actors/")],
tool_registry=my_tool_registry, # satisfies ToolRegistryPort
)
for config in loader.discover():
compiled = compile_actor(config)
# Hand compiled.nodes / compiled.edges to your LangGraph executor
print(compiled.name, compiled.metadata.node_ids)