# Actor YAML Schema Reference ## Overview Actors are the v3 replacement for v2's reactive stream configurations, providing a simpler, more declarative way to define AI agent behaviors. An actor defines what an agent can do, how it processes information, and how it interacts with tools and other actors. **Module:** `cleveragents.actor.schema` **Schema Version:** 1.0 ## Table of Contents - [Actor Types](#actor-types) - [Field Definitions](#field-definitions) - [Tool Node Semantics](#tool-node-semantics) - [Graph Constraints](#graph-constraints) - [Validation Rules](#validation-rules) - [Error Messages](#error-messages) - [Examples](#examples) --- ## 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` - `model` - LLM model identifier (e.g., "gpt-4", "claude-3-opus") **Optional Fields:** - `system_prompt` - System prompt defining agent behavior - `tools` - List of tool references or inline definitions - `context_view` - Role-based context filtering - `memory` - Conversation history settings - `context` - File inclusion settings **Example:** ```yaml name: assistants/code_reviewer type: llm 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) **Optional Fields:** - None (tools-only actors don't need LLM configuration) **Example:** ```yaml 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` - `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:** ```yaml name: workflows/test_driven_dev type: graph 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 behavior 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 backward compatibility #### `model` (conditional) **Type:** `str` **Required for:** `llm`, `graph` actors **Optional for:** `tool` actors (not used) **Description:** LLM model identifier **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 behavior and guidelines **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) **Type:** `list[str | ToolDefinition]` **Required for:** `tool` actors **Optional for:** `llm`, `graph` actors **Description:** Tools available to the actor **Tool Reference Format:** ```yaml tools: - namespace/tool_name # Reference to existing tool ``` **Inline Tool Definition:** ```yaml 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:** ```yaml 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:** ```yaml 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:** ```yaml 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 **Context Views:** - **strategist**: High-level planning view - Project structure - Goals and constraints - 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 - Review feedback - **full**: Complete view (use sparingly) - All available context - Can exceed token limits - Only for critical decision points --- ## Tool Node Semantics ### Tool References Tool references point to existing tools in the tool registry. 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:** ```yaml 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:** ```yaml 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:** ```yaml - 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:** ```yaml - 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:** ```yaml - 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:** ```yaml - id: code_review type: subgraph name: Code Reviewer description: Runs full code review workflow config: actor_path: actors/code_reviewer.yaml ``` **Subgraph Rules:** - Subgraph actors can be of any type (llm, tool, graph) - State is passed to and from the subgraph - Subgraphs enable workflow composition and reuse - Maximum nesting depth: 5 levels ### 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:** ```yaml 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:** ```yaml nodes: - id: planner - id: executor - id: reviewer ``` **Invalid:** ```yaml 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. **Valid:** ```yaml nodes: - id: start - id: process entry_node: start # ✅ 'start' exists ``` **Invalid:** ```yaml nodes: - id: start - id: process 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. **Valid:** ```yaml nodes: - id: start - id: end1 - id: end2 exit_nodes: - end1 - end2 ``` **Invalid:** ```yaml nodes: - id: start - id: end1 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. **Valid:** ```yaml nodes: - id: a - id: b edges: - from_node: a to_node: b ``` **Invalid:** ```yaml nodes: - id: a - id: b 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). **Valid (Linear):** ```yaml edges: - from_node: a to_node: b - from_node: b to_node: c ``` **Valid (Branching):** ```yaml edges: - from_node: a to_node: b - from_node: a to_node: c - from_node: b to_node: d - from_node: c to_node: d ``` **Invalid (Cycle):** ```yaml 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'] ``` **Note:** Conditional edges with retry logic can appear cyclic but are validated at runtime. #### 6. All Nodes Reachable **Rule:** All nodes must be reachable from the entry node. **Valid:** ```yaml entry_node: start edges: - from_node: start to_node: process - from_node: process to_node: end ``` **Invalid:** ```yaml 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 **Example:** ```yaml name: code_reviewer # ❌ Missing namespace ``` **Error:** ``` ValueError: Actor name must be namespaced (namespace/name): code_reviewer ``` **Fix:** ```yaml name: assistants/code_reviewer # ✅ ``` #### TypeError: Missing Required Field **Cause:** LLM or GRAPH actor missing `model` field **Example:** ```yaml name: assistants/helper type: llm # ❌ Missing model field ``` **Error:** ``` ValueError: LLM actors require 'model' field ``` **Fix:** ```yaml name: assistants/helper type: llm model: gpt-4 # ✅ ``` #### ValueError: Empty Tools List **Cause:** TOOL actor with no tools defined **Example:** ```yaml name: utilities/helpers type: tool tools: [] # ❌ Empty list ``` **Error:** ``` ValueError: TOOL actors require at least one tool ``` **Fix:** ```yaml name: utilities/helpers type: tool tools: - files/read_file # ✅ ``` #### ValueError: Missing Route **Cause:** GRAPH actor without route definition **Example:** ```yaml name: workflows/process type: graph model: gpt-4 # ❌ Missing route field ``` **Error:** ``` ValueError: GRAPH actors require 'route' field ``` **Fix:** ```yaml name: workflows/process type: graph model: gpt-4 route: # ✅ nodes: [...] edges: [...] entry_node: start exit_nodes: [end] ``` --- ## Examples ### Example 1: Simple LLM Actor ```yaml name: assistants/code_reviewer type: llm description: Reviews Python code for best practices version: "1.0" 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 ```yaml name: assistants/file_analyzer type: llm description: Analyzes files and generates reports version: "1.0" 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 ```yaml name: workflows/doc_processor type: graph description: Processes documents through multiple stages version: "1.0" 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 ```yaml name: workflows/ci_pipeline type: graph description: CI/CD pipeline with test and deploy stages version: "1.0" 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 ```python from cleveragents.actor.schema import ActorConfigSchema # Load from YAML file actor = ActorConfigSchema.from_yaml_file("actors/code_reviewer.yaml") # Access fields print(actor.name) # assistants/code_reviewer print(actor.type) # ActorType.LLM print(actor.model) # gpt-4 # Validate graph (automatic on load) if actor.type == ActorType.GRAPH: # Validation already done: # - All nodes have unique IDs # - Entry/exit nodes exist # - All edges reference valid nodes # - No cycles detected # - All nodes reachable pass ``` ### Saving Actor Configuration ```python # Create actor programmatically actor = ActorConfigSchema( name="assistants/helper", type=ActorType.LLM, description="A helpful assistant", model="gpt-4", system_prompt="You are a helpful assistant." ) # Save to YAML file actor.to_yaml_file("actors/helper.yaml") ``` --- ## See Also - [ADR-010: Actor and Agent Architecture](../adr/ADR-010-actor-and-agent-architecture.md) - [ADR-011: Tool System](../adr/ADR-011-tool-system.md) - [Tool Schema Reference](../schema/tool.schema.yaml) - [Action Schema Reference](../schema/action.schema.yaml)