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

20 KiB

Actor YAML Schema Reference

Overview

An actor defines what an agent can do, how it processes information, and how it interacts with tools and other actors. This document is the complete schema reference for the actor YAML format parsed, validated, and compiled by this library.

Module: cleveractors.actor.schema
Schema Version: 1.0

Table of Contents


Actor Types

Actors come in three types, each serving different purposes:

LLM Actor

Type: llm
Purpose: Single LLM agent with system prompt and optional tools
Use Case: Simple conversational agents, code reviewers, assistants

Required Fields:

  • name - Namespaced actor name
  • type: llm
  • provider - LLM provider name (e.g., openai, anthropic); resolved at runtime via ProviderRegistryPort
  • model - LLM model identifier (e.g., gpt-4, claude-3-opus)

Optional Fields:

  • system_prompt - System prompt defining agent behaviour
  • tools - List of tool references or inline definitions
  • context_view - Role-based context filtering
  • memory - Conversation history settings
  • context - File inclusion settings

Example:

name: assistants/code_reviewer
type: llm
provider: openai
model: gpt-4
system_prompt: "You are an expert code reviewer..."

TOOL Actor

Type: tool
Purpose: Collection of callable tools without LLM interaction
Use Case: Utility tool bundles, shared tool libraries

Required Fields:

  • name - Namespaced actor name
  • type: tool
  • tools - At least one tool (reference or inline definition)

Example:

name: utilities/file_ops
type: tool
tools:
  - files/read_file
  - files/write_file

GRAPH Actor

Type: graph
Purpose: Multi-node workflow with conditional routing
Use Case: Complex workflows, multi-step processes, agentic loops

Required Fields:

  • name - Namespaced actor name
  • type: graph
  • provider - LLM provider name (e.g., openai, anthropic)
  • model - LLM model for agent nodes
  • route - Complete graph topology definition

Optional Fields:

  • system_prompt - Default prompt for graph-level agents
  • tools - Tools available to all agent nodes
  • context_view - Context filtering for the entire graph
  • memory - Memory settings for the graph
  • context - Context settings

Example:

name: workflows/test_driven_dev
type: graph
provider: openai
model: gpt-4
route:
  nodes: [...]
  edges: [...]
  entry_node: planner
  exit_nodes: [review]

Field Definitions

Top-Level Fields

name (required)

Type: str
Format: namespace/actor_name
Description: Unique identifier for the actor in namespaced format

Validation:

  • Must contain exactly one forward slash (/)
  • Namespace and name must not be empty
  • Should use snake_case for both parts

Valid:

  • assistants/code_reviewer
  • workflows/test_driven_dev
  • utilities/file_operations

Invalid:

  • code_reviewer (missing namespace)
  • assistants/code/reviewer (too many slashes)
  • assistants/ (empty name)

type (required)

Type: ActorType enum
Values: llm, tool, graph
Description: Determines actor execution behaviour and compilation target

description (required)

Type: str
Description: Human-readable description of what the actor does

Best Practices:

  • Start with a verb ("Reviews code...", "Processes documents...")
  • Keep under 200 characters
  • Be specific about the actor's purpose

version (optional)

Type: str
Default: "1.0"
Description: Schema version for compatibility tracking

provider (conditional)

Type: str
Required for: llm, graph actors
Optional for: tool actors (not used)
Description: LLM provider name resolved at runtime by the host via cleveractors.ports.provider_registry.ProviderRegistryPort. See ADR-005 for the runtime resolution contract.

Common Values:

  • OpenAI: openai
  • Anthropic: anthropic
  • Google: google

Validation:

  • LLM and GRAPH actors require 'provider' field if missing for llm or graph actors.

model (conditional)

Type: str
Required for: llm, graph actors
Optional for: tool actors (not used)
Description: LLM model identifier passed to the host's ProviderRegistryPort

Common Values:

  • OpenAI: gpt-4, gpt-4-turbo, gpt-3.5-turbo
  • Anthropic: claude-3-opus, claude-3-sonnet, claude-3-haiku
  • Open source: mistral-large, llama-3-70b

system_prompt (optional)

Type: str
Description: System prompt defining agent behaviour and guidelines. Supports Jinja2 template syntax — see ADR-004 for details.

Best Practices:

  • Use multi-line YAML strings (|) for readability
  • Include role definition ("You are an expert...")
  • List specific tasks and constraints
  • Provide output format guidance

tools (optional / required for tool actors)

Type: list[str | ToolDefinition]
Required for: tool actors
Optional for: llm, graph actors
Description: Tools available to the actor

Tool Reference Format:

tools:
  - namespace/tool_name  # Reference to a named tool

Inline Tool Definition:

tools:
  - name: utils/count_lines
    description: Count lines in a file
    parameters:
      - name: file_path
        type: str
        required: true
    code: |
      def count_lines(file_path: str) -> int:
          with open(file_path, 'r') as f:
              return len(f.readlines())

Tool Definition Fields

ToolParameter

Fields:

  • name (str, required): Parameter name (must be valid Python identifier)
  • type (str, required): Python type annotation (e.g., str, int, list[str])
  • description (str, required): Parameter description
  • required (bool, default=True): Whether parameter is required
  • default (any, optional): Default value for optional parameters

Example:

parameters:
  - name: input_file
    type: str
    description: Path to input file
    required: true
  - name: encoding
    type: str
    description: File encoding
    required: false
    default: utf-8

ToolDefinition

Fields:

  • name (str, required): Tool name in namespace/name format
  • description (str, required): What the tool does
  • parameters (list, optional): List of ToolParameter objects
  • code (str, required): Python code implementing the tool

Validation:

  • Tool name must follow namespace/name format
  • Code must be valid Python
  • Parameter names must be valid identifiers

Memory Configuration

MemoryConfig

Fields:

  • enabled (bool, default=True): Enable conversation memory
  • max_messages (int, optional): Maximum messages to retain (None = unlimited)
  • max_tokens (int, optional): Maximum tokens in history (None = unlimited)
  • summarize_old (bool, default=False): Summarize old messages to save tokens

Example:

memory:
  enabled: true
  max_messages: 50
  max_tokens: 4000
  summarize_old: false

Use Cases:

  • Short conversations: max_messages: 10-20
  • Medium conversations: max_messages: 50, max_tokens: 4000-8000
  • Long workflows: summarize_old: true, max_tokens: 16000

Context Configuration

ContextConfigSchema

Fields:

  • include_files (list[str]): Specific files to include in context
  • include_dirs (list[str]): Directories to include in context
  • exclude_patterns (list[str]): Glob patterns to exclude
  • max_context_tokens (int, optional): Maximum context window size

Example:

context:
  include_files:
    - README.md
    - pyproject.toml
  include_dirs:
    - src/
    - tests/
  exclude_patterns:
    - "**/__pycache__/**"
    - "*.pyc"
    - "**/.git/**"
  max_context_tokens: 8000

ContextView

Type: enum
Values: strategist, executor, reviewer, full
Description: Role-based context filtering hint; consumed by the host's context assembly layer.

Context Views:

  • strategist: High-level planning view

    • Project structure, goals, architecture decisions
    • No implementation details
  • executor: Implementation view

    • Source code, file contents, specific tasks
    • Implementation details
  • reviewer: Validation view

    • Changes and diffs, test results, code quality metrics
  • full: Complete view (use sparingly)

    • All available context; can exceed token limits

Tool Node Semantics

Tool References

Tool references point to named tools that the host resolves via its tool registry at runtime. Use references when:

  • The tool is shared across multiple actors
  • The tool is complex and tested separately
  • The tool requires specific dependencies

Format: namespace/tool_name

Example:

tools:
  - files/read_file
  - testing/run_pytest
  - analysis/extract_entities

Inline Tool Definitions

Inline tools are defined directly in the actor YAML. Use inline tools when:

  • The tool is actor-specific
  • The tool is simple (< 50 lines of code)
  • The tool doesn't require external dependencies

Best Practices:

  1. Keep inline tools simple and focused
  2. Include proper error handling
  3. Add docstrings to the function
  4. Use type hints for all parameters
  5. Validate inputs before processing

Example:

tools:
  - name: utils/count_words
    description: Count words in a text file
    parameters:
      - name: file_path
        type: str
        description: Path to text file
        required: true
    code: |
      def count_words(file_path: str) -> dict:
          """Count words in a file and return statistics."""
          try:
              with open(file_path, 'r', encoding='utf-8') as f:
                  content = f.read()
                  words = content.split()
                  return {
                      "word_count": len(words),
                      "char_count": len(content),
                      "line_count": content.count('\n') + 1
                  }
          except FileNotFoundError:
              return {"error": f"File not found: {file_path}"}
          except Exception as e:
              return {"error": str(e)}

Graph Constraints

Graph Topology

A graph actor's route field defines the complete workflow topology.

RouteDefinition

Fields:

  • nodes (list[NodeDefinition], required): All nodes in the graph
  • edges (list[EdgeDefinition], required): Connections between nodes
  • entry_node (str, required): Starting node ID
  • exit_nodes (list[str], required): Terminal node IDs

Node Types

AGENT Node

Type: agent
Purpose: LLM-powered decision making and content generation
Configuration:

- id: planner
  type: agent
  name: Task Planner
  description: Plans tasks based on requirements
  config:
    model: gpt-4  # Can override graph-level model
    prompt: "You are a task planning expert..."
    tools:
      - files/read_file
      - analysis/extract_requirements

TOOL Node

Type: tool
Purpose: Execute specific tools or functions
Configuration:

- id: run_tests
  type: tool
  name: Test Runner
  description: Executes pytest test suite
  config:
    tool_name: testing/run_pytest
    parameters:
      verbose: true
      coverage: true

CONDITIONAL Node

Type: conditional
Purpose: Route execution based on conditions
Configuration:

- id: check_results
  type: conditional
  name: Result Checker
  description: Routes based on test results
  config:
    conditions:
      - check: "state.get('tests_passed') == True"
        route_to: code_review
      - check: "state.get('tests_passed') == False"
        route_to: fix_errors

Conditional Expressions:

  • Access state with state.get('key')
  • Use Python comparison operators (==, !=, <, >, <=, >=)
  • Combine with boolean operators (and, or, not)
  • Conditions are evaluated in order; first match wins

SUBGRAPH Node

Type: subgraph
Purpose: Embed another actor as a nested workflow
Configuration:

- id: code_review
  type: subgraph
  name: Code Reviewer
  description: Runs full code review workflow
  actor_ref: local/code-reviewer

Subgraph Rules:

  • Reference the actor by its namespaced name via actor_ref
  • State is passed to and from the subgraph
  • Subgraphs enable workflow composition and reuse
  • Circular subgraph references are rejected at compile time

Edge Definition

Fields:

  • from_node (str, required): Source node ID
  • to_node (str, required): Target node ID
  • condition (str, optional): Conditional routing expression
  • priority (int, default=0): Edge priority (higher = evaluated first)

Example:

edges:
  # Unconditional edge
  - from_node: planner
    to_node: executor

  # Conditional edge
  - from_node: executor
    to_node: retry
    condition: "state.get('retry_count', 0) < 3"
    priority: 10

  # Default edge (lower priority)
  - from_node: executor
    to_node: escalate
    priority: 1

Validation Rules

Graph Validation

The schema automatically validates graph topology when loading YAML files.

1. Unique Node IDs

Rule: All node IDs must be unique within a graph.

Valid:

nodes:
  - id: planner
  - id: executor
  - id: reviewer

Invalid:

nodes:
  - id: planner
  - id: executor
  - id: planner  # ❌ Duplicate ID

Error:

ValueError: Duplicate node IDs found: {'planner'}

2. Entry Node Exists

Rule: The entry_node must reference a valid node ID.

Invalid:

nodes:
  - id: start
entry_node: init  # ❌ 'init' doesn't exist

Error:

ValueError: Entry node 'init' not found in nodes

3. Exit Nodes Exist

Rule: All exit_nodes must reference valid node IDs.

Invalid:

exit_nodes:
  - end1
  - finish  # ❌ 'finish' doesn't exist

Error:

ValueError: Exit node 'finish' not found in nodes

4. Edge References Valid

Rule: All edge from_node and to_node must reference valid node IDs.

Invalid:

edges:
  - from_node: a
    to_node: c  # ❌ 'c' doesn't exist

Error:

ValueError: Edge to_node 'c' not found in nodes

5. No Cycles

Rule: Graphs must be acyclic (no circular dependencies).

Invalid:

edges:
  - from_node: a
    to_node: b
  - from_node: b
    to_node: c
  - from_node: c
    to_node: a  # ❌ Cycle: a → b → c → a

Error:

ValueError: Graph contains cycles involving nodes: ['a']

6. All Nodes Reachable

Rule: All nodes must be reachable from the entry node.

Invalid:

entry_node: start
nodes:
  - id: start
  - id: process
  - id: orphan  # ❌ Not reachable from 'start'
edges:
  - from_node: start
    to_node: process

Error:

ValueError: Unreachable nodes detected: {'orphan'}

Error Messages

Common Validation Errors

NameError: Invalid Actor Name

Cause: Actor name doesn't follow namespace/name format

name: code_reviewer  # ❌ Missing namespace

Error:

ValueError: Actor name must be namespaced (namespace/name): code_reviewer

Fix:

name: assistants/code_reviewer  # ✅

TypeError: Missing Required Field

Cause: LLM or GRAPH actor missing model field

Error:

ValueError: LLM actors require 'model' field

Cause: LLM or GRAPH actor missing provider field

Error:

ValueError: LLM and GRAPH actors require 'provider' field

Fix:

provider: openai

ValueError: Empty Tools List

Cause: TOOL actor with no tools defined

Error:

ValueError: TOOL actors require at least one tool

ValueError: Missing Route

Cause: GRAPH actor without route definition

Error:

ValueError: GRAPH actors require 'route' field

Examples

Example 1: Simple LLM Actor

name: assistants/code_reviewer
type: llm
description: Reviews Python code for best practices
version: "1.0"

provider: openai
model: gpt-4
system_prompt: |
  You are an expert Python code reviewer.
  Review code for:
  - PEP 8 compliance
  - Design patterns
  - Potential bugs
  - Performance issues

context_view: reviewer
memory:
  enabled: true
  max_messages: 20

Example 2: LLM with Inline Tools

name: assistants/file_analyzer
type: llm
description: Analyzes files and generates reports
version: "1.0"

provider: openai
model: gpt-4-turbo
system_prompt: "Analyze files and provide insights..."

tools:
  - files/read_file  # Tool reference

  - name: utils/count_lines  # Inline tool
    description: Count lines in a file
    parameters:
      - name: file_path
        type: str
        required: true
    code: |
      def count_lines(file_path: str) -> int:
          with open(file_path, 'r') as f:
              return len(f.readlines())

Example 3: Simple Graph Workflow

name: workflows/doc_processor
type: graph
description: Processes documents through multiple stages
version: "1.0"

provider: openai
model: gpt-3.5-turbo

route:
  nodes:
    - id: extract
      type: tool
      name: Text Extractor
      description: Extracts text from documents
      config:
        tool_name: documents/extract_text

    - id: analyze
      type: agent
      name: Analyzer
      description: Analyzes content
      config:
        model: gpt-3.5-turbo
        prompt: "Analyze the document content..."

    - id: summarize
      type: agent
      name: Summarizer
      description: Creates summary
      config:
        model: gpt-3.5-turbo
        prompt: "Summarize in 3-5 bullet points..."

  edges:
    - from_node: extract
      to_node: analyze
    - from_node: analyze
      to_node: summarize

  entry_node: extract
  exit_nodes:
    - summarize

Example 4: Complex Graph with Conditionals

name: workflows/ci_pipeline
type: graph
description: CI/CD pipeline with test and deploy stages
version: "1.0"

provider: openai
model: gpt-4

route:
  nodes:
    - id: build
      type: tool
      name: Builder
      description: Builds the project
      config:
        tool_name: ci/build

    - id: test
      type: tool
      name: Test Runner
      description: Runs test suite
      config:
        tool_name: ci/run_tests

    - id: check_tests
      type: conditional
      name: Test Result Checker
      description: Check if tests passed
      config:
        conditions:
          - check: "state.get('tests_passed') == True"
            route_to: deploy
          - check: "state.get('tests_passed') == False"
            route_to: notify_failure

    - id: deploy
      type: tool
      name: Deployer
      description: Deploys to production
      config:
        tool_name: ci/deploy

    - id: notify_failure
      type: tool
      name: Notifier
      description: Sends failure notification
      config:
        tool_name: notifications/send_alert

  edges:
    - from_node: build
      to_node: test
    - from_node: test
      to_node: check_tests
    # Conditional routing handled by check_tests node

  entry_node: build
  exit_nodes:
    - deploy
    - notify_failure

Usage

Loading Actor Configuration

from cleveractors.actor.schema import ActorConfigSchema
from cleveractors.actor.yaml_loader import load_yaml_text

# Load from file
with open("actors/code_reviewer.yaml") as f:
    raw = load_yaml_text(f.read())
actor = ActorConfigSchema.model_validate(raw)

# Access fields
print(actor.name)   # assistants/code_reviewer
print(actor.type)   # ActorType.LLM
print(actor.model)  # gpt-4

# Validation is automatic on load:
# - All nodes have unique IDs
# - Entry/exit nodes exist
# - All edges reference valid nodes
# - No cycles detected
# - All nodes reachable

Compiling an Actor

from cleveractors.actor.compiler import compile_actor

compiled = compile_actor(actor)
print(compiled.metadata.node_ids)   # list of all node IDs
print(compiled.metadata.lsp_bindings)  # extracted LSP bindings

See Also