forked from HAL9000/cleveragents-core
c47e6445d0
Add ActorCompiler module that translates GRAPH-type ActorConfigSchema definitions into LangGraph NodeConfig/Edge structures with LSP binding metadata. Includes subgraph resolution with cross-actor cycle detection, entry/exit validation, and CompilationMetadata for diagnostics. New files: - src/cleveragents/actor/compiler.py: Core compiler with compile_actor() - features/actor_compiler.feature: 13 Behave scenarios - features/steps/actor_compiler_steps.py: Step definitions - robot/actor_compiler.robot: 4 Robot smoke tests - benchmarks/actor_compiler_bench.py: ASV performance benchmarks - docs/reference/actor_compiler.md: Compilation pipeline reference Modified: - src/cleveragents/actor/__init__.py: Export compiler types - vulture_whitelist.py: Whitelist new public API ISSUES CLOSED: #158
107 lines
3.7 KiB
Markdown
107 lines
3.7 KiB
Markdown
# Actor Compiler
|
|
|
|
The actor compiler translates hierarchical YAML-defined GRAPH actors into
|
|
LangGraph `StateGraph` node/edge structures that can be executed by the
|
|
CleverAgents runtime.
|
|
|
|
## 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 and CLI inspection.
|
|
|
|
## Node Binding
|
|
|
|
| Actor Node Type | LangGraph NodeType | Notes |
|
|
|---|---|---|
|
|
| `agent` | `AGENT` | LLM invocation node |
|
|
| `tool` | `TOOL` | Tool execution node |
|
|
| `conditional` | `CONDITIONAL` | Routing node |
|
|
| `subgraph` | `SUBGRAPH` | Nested actor reference |
|
|
|
|
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.
|
|
|
|
**Parameters:**
|
|
- `config` — The actor configuration (must be `ActorType.GRAPH`).
|
|
- `actor_resolver` — Optional callable `(name: str) -> ActorConfigSchema | None`
|
|
for resolving subgraph references.
|
|
|
|
**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 |
|