forked from cleveragents/cleveragents-core
Merge branch 'master' into feature/m3-agent-skills-loader
This commit is contained in:
@@ -0,0 +1,310 @@
|
||||
# Actor Configuration Reference
|
||||
|
||||
Practical guide to writing actor YAML configuration files with hierarchical
|
||||
graph examples and common error cases.
|
||||
|
||||
**Module:** `cleveragents.actor.schema` / `cleveragents.actor.loader`
|
||||
|
||||
Related references:
|
||||
- [Actor YAML Schema](actors_schema.md) — full field listing
|
||||
- [Actor Hierarchy Extensions](actor_hierarchy.md) — LSP bindings and tool sources
|
||||
- [Actor Loader](actors_loading.md) — discovery and caching
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Actor Configuration Reference](#actor-configuration-reference)
|
||||
- [Basic Structure](#basic-structure)
|
||||
- [Hierarchical Graph Example](#hierarchical-graph-example)
|
||||
- [Node Types](#node-types)
|
||||
- [Graph Topology Rules](#graph-topology-rules)
|
||||
- [Error Cases](#error-cases)
|
||||
|
||||
---
|
||||
|
||||
## Basic Structure
|
||||
|
||||
Every actor YAML file must include `name`, `type`, and `description`.
|
||||
The `name` must follow the `namespace/identifier` format.
|
||||
|
||||
```yaml
|
||||
name: local/my-actor # Required — namespaced
|
||||
type: llm # Required — llm | tool | graph
|
||||
description: What it does # Required
|
||||
version: "1.0" # Optional
|
||||
model: gpt-4 # Required for llm and graph types
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hierarchical Graph Example
|
||||
|
||||
A graph actor defines a multi-node workflow with conditional routing,
|
||||
per-node LSP bindings, and tool-source references.
|
||||
|
||||
```yaml
|
||||
name: workflows/dev-pipeline
|
||||
type: graph
|
||||
description: Multi-agent development pipeline
|
||||
version: "1.0"
|
||||
model: gpt-4
|
||||
|
||||
# Actor-level skill and LSP declarations
|
||||
skills:
|
||||
- local/file-ops
|
||||
- local/git-ops
|
||||
lsp:
|
||||
- local/pyright
|
||||
|
||||
route:
|
||||
nodes:
|
||||
- id: planner
|
||||
type: agent
|
||||
name: Planner
|
||||
description: Plans the implementation strategy
|
||||
config:
|
||||
model: gpt-4
|
||||
prompt: "Analyze requirements and create a plan."
|
||||
# Per-node LSP binding (overrides actor-level default)
|
||||
lsp_binding:
|
||||
server: local/pyright
|
||||
languages:
|
||||
- python
|
||||
capabilities:
|
||||
- diagnostics
|
||||
# Per-node tool sources
|
||||
tool_sources:
|
||||
- type: skill
|
||||
name: local/file-ops
|
||||
|
||||
- id: implementer
|
||||
type: agent
|
||||
name: Implementer
|
||||
description: Implements the plan
|
||||
config:
|
||||
model: gpt-4
|
||||
prompt: "Implement the changes per the plan."
|
||||
lsp_binding:
|
||||
auto: true
|
||||
tool_sources:
|
||||
- type: skill
|
||||
name: local/file-ops
|
||||
- type: skill
|
||||
name: local/git-ops
|
||||
- type: mcp
|
||||
name: local/filesystem
|
||||
|
||||
- id: reviewer
|
||||
type: subgraph
|
||||
name: Code Reviewer
|
||||
description: Delegates to the code-review actor
|
||||
actor_ref: local/code-reviewer # namespaced reference to another actor
|
||||
|
||||
- id: gate
|
||||
type: conditional
|
||||
name: Quality Gate
|
||||
description: Routes to reviewer or re-plans based on lint result
|
||||
config:
|
||||
conditions:
|
||||
- check: "state.get('lint_ok') == True"
|
||||
route_to: reviewer
|
||||
- check: "state.get('lint_ok') == False"
|
||||
route_to: planner
|
||||
|
||||
edges:
|
||||
- from_node: planner
|
||||
to_node: implementer
|
||||
- from_node: implementer
|
||||
to_node: gate
|
||||
- from_node: gate
|
||||
to_node: planner # explicit back-edge for retry path
|
||||
- from_node: gate
|
||||
to_node: reviewer
|
||||
|
||||
entry_node: planner
|
||||
exit_nodes:
|
||||
- reviewer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Node Types
|
||||
|
||||
| Type | Purpose | Key config fields |
|
||||
|------|---------|-------------------|
|
||||
| `agent` | LLM-driven reasoning node | `model`, `prompt`, `tools` |
|
||||
| `tool` | Runs a specific tool call | `tool_name`, `parameters` |
|
||||
| `conditional` | Routes to different nodes based on state | `conditions[].check`, `conditions[].route_to` |
|
||||
| `subgraph` | Delegates to another actor entirely | `actor_ref` |
|
||||
|
||||
### Conditional Node Routing
|
||||
|
||||
Conditional nodes use Python expressions over `state` to route the workflow.
|
||||
The `route_to` targets are counted as reachable even without explicit edges.
|
||||
|
||||
```yaml
|
||||
- id: branch
|
||||
type: conditional
|
||||
name: Branch
|
||||
description: Decides next step
|
||||
config:
|
||||
conditions:
|
||||
- check: "state.get('success') == True"
|
||||
route_to: done
|
||||
- check: "state.get('success') == False"
|
||||
route_to: retry
|
||||
```
|
||||
|
||||
### Subgraph Node
|
||||
|
||||
Subgraph nodes delegate execution to another actor by namespaced name.
|
||||
Use `actor_ref` (not `config.actor_path`).
|
||||
|
||||
```yaml
|
||||
- id: review_step
|
||||
type: subgraph
|
||||
name: Review
|
||||
description: Runs the review sub-workflow
|
||||
actor_ref: local/reviewer # correct: namespaced actor reference
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Graph Topology Rules
|
||||
|
||||
The loader enforces these constraints on every graph actor:
|
||||
|
||||
| Rule | Error trigger |
|
||||
|------|--------------|
|
||||
| Unique node IDs | Two nodes share the same `id` |
|
||||
| Entry node exists | `entry_node` references an `id` not in `nodes` |
|
||||
| Exit nodes exist | Any `exit_nodes` entry references a missing `id` |
|
||||
| Edge targets exist | `from_node` or `to_node` reference a missing `id` |
|
||||
| Nodes are reachable | A node has no path from `entry_node` via edges or conditional routing |
|
||||
| No cycles | A non-conditional cycle exists in the edge graph |
|
||||
|
||||
---
|
||||
|
||||
## Error Cases
|
||||
|
||||
### Naming Errors
|
||||
|
||||
**Actor name missing namespace:**
|
||||
```yaml
|
||||
name: my-actor # wrong — must be namespace/name
|
||||
```
|
||||
Error: `name must be in 'namespace/name' format`
|
||||
|
||||
Fix: use a namespaced name like `local/my-actor` or `workflows/my-actor`.
|
||||
|
||||
---
|
||||
|
||||
### LLM Actor Without Model
|
||||
|
||||
```yaml
|
||||
name: local/my-actor
|
||||
type: llm
|
||||
description: Assistant
|
||||
# model: missing
|
||||
```
|
||||
Error: `llm and graph types require 'model'`
|
||||
|
||||
---
|
||||
|
||||
### GRAPH Actor Without Route
|
||||
|
||||
```yaml
|
||||
name: local/pipeline
|
||||
type: graph
|
||||
description: Pipeline
|
||||
model: gpt-4
|
||||
# route: missing
|
||||
```
|
||||
Error: `graph type requires 'route'`
|
||||
|
||||
---
|
||||
|
||||
### Duplicate Node IDs
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: step_a
|
||||
...
|
||||
- id: step_a # duplicate
|
||||
...
|
||||
```
|
||||
Error: `Duplicate node IDs: 'step_a'`
|
||||
|
||||
Fix: give each node a unique `id`.
|
||||
|
||||
---
|
||||
|
||||
### Missing Entry Node
|
||||
|
||||
```yaml
|
||||
route:
|
||||
nodes:
|
||||
- id: node_a
|
||||
...
|
||||
entry_node: node_x # node_x does not exist
|
||||
```
|
||||
Error: `Entry node 'node_x' not found in route.entry_node`
|
||||
|
||||
---
|
||||
|
||||
### Invalid Edge Target
|
||||
|
||||
```yaml
|
||||
edges:
|
||||
- from_node: node_a
|
||||
to_node: node_z # node_z does not exist
|
||||
```
|
||||
Error: `Edge to_node 'node_z' not found at route.edges[0]`
|
||||
|
||||
---
|
||||
|
||||
### Unreachable Node
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: node_a
|
||||
- id: node_b
|
||||
- id: node_c # no edge or conditional route_to points here
|
||||
edges:
|
||||
- from_node: node_a
|
||||
to_node: node_b
|
||||
entry_node: node_a
|
||||
```
|
||||
Error: `route: nodes 'node_c' are unreachable from entry node 'node_a'`
|
||||
|
||||
Fix: add an edge from a reachable node to `node_c`, or remove `node_c` from
|
||||
`nodes` if it is not needed.
|
||||
|
||||
---
|
||||
|
||||
### YAML Parse Error
|
||||
|
||||
A malformed YAML file produces a parse error with the location:
|
||||
|
||||
```
|
||||
Invalid YAML in bad.yaml at line 3, column 5: mapping values are not allowed here
|
||||
```
|
||||
|
||||
Fix: check the indicated line and correct the YAML syntax.
|
||||
|
||||
---
|
||||
|
||||
### Schema Validation Error Format
|
||||
|
||||
When a YAML file is syntactically valid but fails schema validation, the
|
||||
loader reports precise field paths:
|
||||
|
||||
```
|
||||
Schema validation failed for actor.yaml:
|
||||
type: Input should be 'llm', 'tool' or 'graph'
|
||||
route.nodes.0.id: String should match pattern '^[a-zA-Z0-9_-]+$'
|
||||
Hint: see docs/reference/actor_config.md for the correct schema format.
|
||||
```
|
||||
|
||||
Each line shows the dotted field path and the validation message.
|
||||
@@ -0,0 +1,165 @@
|
||||
# Actor Hierarchy and Advanced YAML Extensions
|
||||
|
||||
This document covers the advanced actor YAML schema extensions introduced
|
||||
in **M2.1.actor-yaml**: per-node LSP bindings, tool-source references,
|
||||
subgraph actor references, and actor-level skill/LSP fields.
|
||||
|
||||
## Overview
|
||||
|
||||
Actor YAML configurations can define multi-node graph workflows. The
|
||||
M2.1 extensions add fine-grained control over:
|
||||
|
||||
| Feature | Scope | Purpose |
|
||||
|---------|-------|---------|
|
||||
| `lsp_binding` | Per-node | Bind specific LSP servers to individual graph nodes |
|
||||
| `tool_sources` | Per-node | Declare where a node's tools come from (skills, MCP, builtins) |
|
||||
| `actor_ref` | Per-node (subgraph) | Reference another actor by namespaced name |
|
||||
| `skills` | Actor-level | List of skill references available to the actor |
|
||||
| `lsp` | Actor-level | Default LSP server bindings for the actor |
|
||||
| `lsp_capabilities` | Actor-level | Filter which LSP capabilities are exposed |
|
||||
| `lsp_context_enrichment` | Actor-level | Control automatic context injection |
|
||||
|
||||
## Per-Node LSP Binding
|
||||
|
||||
Different nodes in a graph can have different LSP configurations:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: strategist
|
||||
type: agent
|
||||
name: Strategy Planner
|
||||
description: Plans with read-only LSP
|
||||
lsp_binding:
|
||||
server: local/pyright
|
||||
languages:
|
||||
- python
|
||||
capabilities:
|
||||
- diagnostics
|
||||
- hover
|
||||
|
||||
- id: implementer
|
||||
type: agent
|
||||
name: Implementer
|
||||
description: Full LSP auto-binding
|
||||
lsp_binding:
|
||||
auto: true
|
||||
```
|
||||
|
||||
### `NodeLspBinding` Fields
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `server` | `string` | `null` | Namespaced LSP server name (e.g. `local/pyright`) |
|
||||
| `languages` | `list[string]` | `[]` | Languages for language-based resolution |
|
||||
| `auto` | `bool` | `false` | Auto-resolve from project resources |
|
||||
| `capabilities` | `list[string]` | `null` | Capability filter for this node |
|
||||
|
||||
## Tool-Source References
|
||||
|
||||
Nodes can declare their tool sources explicitly:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: executor
|
||||
type: agent
|
||||
name: Executor
|
||||
description: Has multiple tool sources
|
||||
tool_sources:
|
||||
- type: skill
|
||||
name: local/file-ops
|
||||
- type: mcp
|
||||
name: local/filesystem
|
||||
- type: builtin
|
||||
group: git_operations
|
||||
```
|
||||
|
||||
### `ToolSourceRef` Fields
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `type` | `string` | Yes | `skill`, `mcp`, `builtin`, or `custom` |
|
||||
| `name` | `string` | No | Namespaced name (for `skill` and `mcp`) |
|
||||
| `group` | `string` | No | Group identifier (for `builtin`) |
|
||||
|
||||
## Subgraph Actor References
|
||||
|
||||
Subgraph nodes can reference other actors by namespaced name:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: review
|
||||
type: subgraph
|
||||
name: Code Review
|
||||
description: Delegates to code-reviewer
|
||||
actor_ref: local/code-reviewer
|
||||
```
|
||||
|
||||
The `actor_ref` field must be in `namespace/name` format.
|
||||
|
||||
## Actor-Level Fields
|
||||
|
||||
### `skills`
|
||||
|
||||
```yaml
|
||||
skills:
|
||||
- local/file-ops
|
||||
- local/git-ops
|
||||
```
|
||||
|
||||
### `lsp`
|
||||
|
||||
Explicit binding (list of server names):
|
||||
|
||||
```yaml
|
||||
lsp:
|
||||
- local/pyright
|
||||
- local/clangd
|
||||
```
|
||||
|
||||
Auto binding:
|
||||
|
||||
```yaml
|
||||
lsp:
|
||||
auto: true
|
||||
```
|
||||
|
||||
### `lsp_capabilities`
|
||||
|
||||
```yaml
|
||||
lsp_capabilities:
|
||||
- diagnostics
|
||||
- hover
|
||||
- definitions
|
||||
```
|
||||
|
||||
Or expose all:
|
||||
|
||||
```yaml
|
||||
lsp_capabilities: all
|
||||
```
|
||||
|
||||
### `lsp_context_enrichment`
|
||||
|
||||
```yaml
|
||||
lsp_context_enrichment:
|
||||
diagnostics: true
|
||||
type_annotations: false
|
||||
max_diagnostics_per_file: 50
|
||||
```
|
||||
|
||||
## Validation Error Messages
|
||||
|
||||
Validation errors now include field-path context:
|
||||
|
||||
| Error | Example Message |
|
||||
|-------|-----------------|
|
||||
| Bad entry node | `Entry node 'missing' not found in route.entry_node. Valid node IDs: [a, b]` |
|
||||
| Bad exit node | `Exit node 'missing' not found in route.exit_nodes. Valid node IDs: [a, b]` |
|
||||
| Bad edge ref | `Edge from_node 'ghost' not found at route.edges[0]. Valid node IDs: [a, b]` |
|
||||
| Duplicate IDs | `route.nodes: Duplicate node IDs found: ['dup']. Each node ID must be unique.` |
|
||||
| Cycle | `route: graph contains a cycle involving nodes: [a → b]. Hint: remove or redirect edges.` |
|
||||
|
||||
## Complete Example
|
||||
|
||||
See `examples/actors/hierarchical_workflow.yaml` for a full working example
|
||||
combining all these features.
|
||||
Reference in New Issue
Block a user