# Actor Compiler The actor compiler translates hierarchical YAML-defined GRAPH actors into LangGraph `StateGraph` node/edge structures that can be executed by the host application. **Module:** `cleveractors.actor.compiler` ## Compilation Pipeline 1. **Input validation** — The compiler accepts an `ActorConfigSchema` with `type=GRAPH` and a populated `route` field. Non-GRAPH types are rejected with `ActorCompilationError`. 2. **Reference validation** — All node IDs referenced in edges, entry, and exit points are checked against the declared node set. 3. **Intra-graph cycle detection** — The route's `detect_cycles()` method verifies the node graph is acyclic. 4. **Cross-actor subgraph cycle detection** — When an optional `actor_resolver` is provided, the compiler follows `SUBGRAPH` node references recursively and detects cycles across actor boundaries (e.g. actor A → actor B → actor A). 5. **Node mapping** — Each `NodeDefinition` is mapped to a LangGraph `NodeConfig` with the appropriate `NodeType` (AGENT, TOOL, CONDITIONAL, SUBGRAPH). 6. **Edge mapping** — Each `EdgeDefinition` is mapped to a LangGraph `Edge`. Conditional expressions are preserved in `edge.condition`. 7. **LSP binding extraction** — Per-node `lsp_bindings` config entries are extracted into `LspBinding` objects and stored in compilation metadata. 8. **Metadata assembly** — The compiler returns a `CompiledActor` containing the node map, edge list, entry point, and a `CompilationMetadata` object for diagnostics. ## Node Binding | Actor Node Type | LangGraph NodeType | Notes | |---|---|---| | `agent` | `AGENT` | LLM invocation node; resolved at runtime via `ProviderRegistryPort`. Graph-level `provider`, `model`, and `system_prompt` act as per-node defaults (see below). | | `tool` | `TOOL` | Tool execution node; reference verified at load time via `ToolRegistryPort` | | `conditional` | `CONDITIONAL` | Routing node | | `subgraph` | `SUBGRAPH` | Nested actor reference | #### AGENT node defaults Graph-level `provider`, `model`, and `system_prompt` are propagated as fallback defaults into each AGENT node's `NodeConfig.metadata` via `setdefault`. Per-node `config.provider` / `config.model` / `config.system_prompt` override them. The `system_prompt` key is only set in metadata when the actor defines a top-level `system_prompt` value (including empty string); actors without the field do not carry the key. At runtime, `Node._execute_agent()` injects `metadata["system_prompt"]` (when present) into the context dict passed to `agent.process_message()`, so host agents can read it without a direct reference to the raw `ActorConfigSchema`. Per- execution `state.metadata["system_prompt"]` overrides the compiled default. LSP bindings are declared per-node in the `config.lsp_bindings` list: ```yaml nodes: - id: coder type: agent name: Code Writer description: Writes Python code config: agent: coder_agent lsp_bindings: - lsp_server_name: local/pyright languages: [python] auto_detect: true ``` ## Error Modes | Error | Class | When | |---|---|---| | Non-GRAPH type | `ActorCompilationError` | `config.type != GRAPH` | | Missing route | `ActorCompilationError` | `config.route is None` | | Missing node | `MissingNodeError` | Edge references unknown node | | Invalid entry/exit | `InvalidEntryExitError` | Entry/exit node not in graph | | Intra-graph cycle | `SubgraphCycleError` | Nodes form a cycle | | Cross-actor cycle | `SubgraphCycleError` | Subgraph refs form a cycle | ## API Reference ### `compile_actor(config, *, actor_resolver=None) -> CompiledActor` Compile an `ActorConfigSchema` into a LangGraph-ready bundle. ```python from cleveractors.actor.compiler import compile_actor from cleveractors.actor.schema import ActorConfigSchema cfg = ActorConfigSchema.model_validate(yaml.safe_load(yaml_text)) compiled = compile_actor(cfg) ``` **Parameters:** - `config` — The actor configuration (must be `ActorType.GRAPH`). - `actor_resolver` — Optional callable `(name: str) -> ActorConfigSchema | None` for resolving subgraph references during cross-actor cycle detection. **Returns:** `CompiledActor` with nodes, edges, and metadata. ### `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 | ## See Also - [Actor Abstraction Definition](../adr/ADR-003-actor-abstraction-definition.md) — what an actor is - [Actor YAML Schema](actors_schema.md) — full field reference - [Actor Configuration Guide](actor_config.md) — practical authoring guide