Files
hurui200320 15e81e58f1
CI / dead_code (pull_request) Successful in 40s
CI / security (pull_request) Successful in 1m10s
CI / coverage (pull_request) Successful in 1m11s
CI / typecheck (pull_request) Successful in 1m19s
CI / unit_tests (pull_request) Successful in 1m18s
CI / lint (pull_request) Successful in 1m20s
CI / build (pull_request) Successful in 23s
CI / lint (push) Successful in 51s
CI / typecheck (push) Successful in 47s
CI / unit_tests (push) Successful in 49s
CI / coverage (push) Successful in 53s
CI / dead_code (push) Successful in 26s
CI / build (push) Successful in 26s
CI / security (push) Successful in 42s
fix: sync doc with extraction scope, remove boundary violation, add ProviderRegistryPort
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
2026-05-21 10:10:37 +00:00

7.4 KiB

Actor Configuration Reference

Practical guide to writing actor YAML configuration files with hierarchical graph examples and common error cases.

Module: cleveractors.actor.schema / cleveractors.actor.loader

Related references:


Table of Contents


Basic Structure

Every actor YAML file must include name, type, and description. The name must follow the namespace/identifier format.

name: local/my-actor       # Required — namespaced
type: llm                  # Required — llm | tool | graph
description: What it does  # Required
version: "1.0"             # Optional
provider: openai           # Required for llm and graph types
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.

name: workflows/dev-pipeline
type: graph
description: Multi-agent development pipeline
version: "1.0"
provider: openai
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 provider, 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.

- 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).

- 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:

name: my-actor     # wrong — must be namespace/name

Error: Actor name must be namespaced (namespace/name): my-actor

Fix: use a namespaced name like local/my-actor or workflows/my-actor.


LLM Actor Without Model

name: local/my-actor
type: llm
description: Assistant
# model: missing

Error: LLM actors require 'model' field


LLM/GRAPH Actor Without Provider

name: local/my-actor
type: llm
description: Assistant
model: gpt-4
# provider: missing

Error: LLM and GRAPH actors require 'provider' field


GRAPH Actor Without Route

name: local/pipeline
type: graph
description: Pipeline
provider: openai
model: gpt-4
# route: missing

Error: GRAPH actors require 'route' field


Duplicate Node IDs

nodes:
  - id: step_a
    ...
  - id: step_a    # duplicate
    ...

Error: Duplicate node IDs: 'step_a'

Fix: give each node a unique id.


Missing Entry Node

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

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

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.