e03fd2956d
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 18s
CI / lint (pull_request) Failing after 18s
CI / helm (pull_request) Successful in 24s
CI / typecheck (pull_request) Failing after 52s
CI / security (pull_request) Failing after 53s
CI / coverage (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
CI / unit_tests (pull_request) Failing after 1m48s
CI / docker (pull_request) Has been skipped
CI / quality (pull_request) Successful in 3m42s
CI / e2e_tests (pull_request) Failing after 13m56s
CI / integration_tests (pull_request) Failing after 21m12s
CI / status-check (pull_request) Failing after 2s
Add missing provider: field to all actor examples in examples/actors/. Fix llm_with_tools.yaml actor name from assistants/file_analyzer to local/assistants-file_analyzer (custom actors must use local/ namespace and cannot contain two slashes). Add validate-all command to helper_actor_examples.py that uses ActorLoader to validate all examples via business logic checks. Add integration test Validate All Actor Examples Import Without Errors to actor_examples.robot that confirms every example in examples/actors/ can be imported without errors. ISSUES CLOSED: #1504
281 lines
8.4 KiB
Python
281 lines
8.4 KiB
Python
"""Robot Framework helper for actor YAML examples validation.
|
|
|
|
Provides CLI-style interface for Robot to validate actor examples,
|
|
check patterns, and verify documentation completeness.
|
|
|
|
Usage:
|
|
python robot/helper_actor_examples.py validate <yaml_file>
|
|
python robot/helper_actor_examples.py validate-invalid <yaml_file>
|
|
python robot/helper_actor_examples.py count-examples <directory>
|
|
python robot/helper_actor_examples.py check-pattern <yaml_file> <pattern>
|
|
python robot/helper_actor_examples.py check-docs <doc_file>
|
|
python robot/helper_actor_examples.py check-doc-patterns <doc_file>
|
|
python robot/helper_actor_examples.py validate-all <directory>
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Ensure the src directory is on the import path.
|
|
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
from cleveragents.actor.loader import ActorLoader # noqa: E402
|
|
from cleveragents.actor.schema import ActorConfigSchema, ActorType # noqa: E402
|
|
|
|
|
|
def validate_actor(yaml_path: str) -> int:
|
|
"""Validate actor YAML and print details."""
|
|
try:
|
|
config = ActorConfigSchema.from_yaml_file(yaml_path)
|
|
print("actor-ok")
|
|
print(f"name:{config.name}")
|
|
print(f"type:{config.type.value}")
|
|
|
|
if config.tools:
|
|
print("has-tools")
|
|
|
|
if config.skills:
|
|
print("has-skills")
|
|
|
|
if config.route:
|
|
print("has-route")
|
|
|
|
if config.env_vars:
|
|
print("has-env-vars")
|
|
|
|
if config.memory:
|
|
print("has-memory")
|
|
|
|
if config.context_view:
|
|
print(f"context-view:{config.context_view.value}")
|
|
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"actor-fail: {exc}")
|
|
return 1
|
|
|
|
|
|
def validate_invalid_actor(yaml_path: str) -> int:
|
|
"""Expect validation to fail."""
|
|
try:
|
|
ActorConfigSchema.from_yaml_file(yaml_path)
|
|
print("unexpected-success")
|
|
return 1
|
|
except Exception as exc:
|
|
print("expected-fail")
|
|
error_msg = str(exc).lower()
|
|
if "namespace" in error_msg or "name" in error_msg:
|
|
print("namespace")
|
|
if "model" in error_msg:
|
|
print("model")
|
|
if "tool" in error_msg:
|
|
print("tool")
|
|
if "route" in error_msg:
|
|
print("route")
|
|
return 0
|
|
|
|
|
|
def count_examples(directory: str) -> int:
|
|
"""Count YAML example files."""
|
|
try:
|
|
examples_dir = Path(directory)
|
|
yaml_files = list(examples_dir.glob("*.yaml"))
|
|
print(f"example-count:{len(yaml_files)}")
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"count-fail: {exc}")
|
|
return 1
|
|
|
|
|
|
def check_pattern(yaml_path: str, pattern: str) -> int:
|
|
"""Check if actor follows a specific pattern."""
|
|
try:
|
|
config = ActorConfigSchema.from_yaml_file(yaml_path)
|
|
|
|
if pattern == "strategist":
|
|
# Strategist pattern: large context, read-only tools, memory enabled
|
|
if config.memory and config.memory.enabled:
|
|
print("has-memory")
|
|
if config.context_view:
|
|
print(f"context-view:{config.context_view.value}")
|
|
print(f"pattern-ok:{pattern}")
|
|
|
|
elif pattern == "tool-only":
|
|
# Tool-only pattern: no model, has tools
|
|
if config.type == ActorType.TOOL:
|
|
print("pattern-ok:tool-only")
|
|
if not config.model:
|
|
print("no-model")
|
|
|
|
elif pattern == "graph":
|
|
# Graph pattern: has route with entry/exit nodes
|
|
if config.route:
|
|
print("pattern-ok:graph")
|
|
if config.route.entry_node:
|
|
print("has-entry-node")
|
|
if config.route.exit_nodes:
|
|
print("has-exit-nodes")
|
|
|
|
elif pattern == "hierarchical":
|
|
# Hierarchical pattern: graph with subgraph nodes
|
|
if config.route:
|
|
print("pattern-ok:hierarchical")
|
|
# Check for subgraph nodes
|
|
from cleveragents.actor.schema import NodeType
|
|
|
|
subgraph_nodes = [
|
|
node
|
|
for node in config.route.nodes
|
|
if node.type == NodeType.SUBGRAPH
|
|
]
|
|
if subgraph_nodes:
|
|
print("has-subgraph")
|
|
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"pattern-check-fail: {exc}")
|
|
return 1
|
|
|
|
|
|
def check_docs(doc_file: str) -> int:
|
|
"""Check if documentation references all example files."""
|
|
try:
|
|
doc_path = Path(doc_file)
|
|
doc_content = doc_path.read_text()
|
|
|
|
example_files = [
|
|
"simple_llm.yaml",
|
|
"llm_with_tools.yaml",
|
|
"estimator.yaml",
|
|
"tool_collection.yaml",
|
|
"simple_graph.yaml",
|
|
"graph_workflow.yaml",
|
|
]
|
|
|
|
for filename in example_files:
|
|
if filename in doc_content:
|
|
print(f"doc-references:{filename}")
|
|
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"doc-check-fail: {exc}")
|
|
return 1
|
|
|
|
|
|
def check_doc_patterns(doc_file: str) -> int:
|
|
"""Check if documentation includes all required patterns."""
|
|
try:
|
|
doc_path = Path(doc_file)
|
|
doc_content = doc_path.read_text().lower()
|
|
|
|
patterns = [
|
|
"strategist",
|
|
"executor",
|
|
"reviewer",
|
|
"tool-only",
|
|
"validation",
|
|
"hierarchical",
|
|
]
|
|
|
|
for pattern in patterns:
|
|
if pattern in doc_content:
|
|
print(f"has-pattern:{pattern}")
|
|
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"doc-pattern-check-fail: {exc}")
|
|
return 1
|
|
|
|
|
|
def validate_all_examples(directory: str) -> int:
|
|
"""Validate all actor examples in a directory via ActorLoader business logic.
|
|
|
|
Uses ActorLoader (which applies ActorConfigSchema validation) to discover
|
|
and validate every YAML file in the given directory. Prints one
|
|
``actor-imported:<name>`` line per successfully loaded actor and a final
|
|
``all-examples-ok:<count>`` summary line. Returns 1 on any failure.
|
|
"""
|
|
try:
|
|
examples_dir = Path(directory)
|
|
loader = ActorLoader(search_roots=[examples_dir])
|
|
actors = loader.discover()
|
|
for actor in actors:
|
|
print(f"actor-imported:{actor.name}")
|
|
print(f"all-examples-ok:{len(actors)}")
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"validate-all-fail: {exc}")
|
|
return 1
|
|
|
|
|
|
def main() -> int:
|
|
"""Entry point called by Robot Framework ``Run Process``."""
|
|
if len(sys.argv) < 2:
|
|
print(
|
|
"Usage: helper_actor_examples.py <command> [args...]\n"
|
|
"Commands:\n"
|
|
" validate <file>\n"
|
|
" validate-invalid <file>\n"
|
|
" count-examples <directory>\n"
|
|
" check-pattern <file> <pattern>\n"
|
|
" check-docs <doc_file>\n"
|
|
" check-doc-patterns <doc_file>\n"
|
|
" validate-all <directory>"
|
|
)
|
|
return 1
|
|
|
|
command = sys.argv[1]
|
|
|
|
if command == "validate":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: validate <yaml_file>")
|
|
return 1
|
|
return validate_actor(sys.argv[2])
|
|
|
|
if command == "validate-invalid":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: validate-invalid <yaml_file>")
|
|
return 1
|
|
return validate_invalid_actor(sys.argv[2])
|
|
|
|
if command == "count-examples":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: count-examples <directory>")
|
|
return 1
|
|
return count_examples(sys.argv[2])
|
|
|
|
if command == "check-pattern":
|
|
if len(sys.argv) < 4:
|
|
print("Usage: check-pattern <yaml_file> <pattern>")
|
|
return 1
|
|
return check_pattern(sys.argv[2], sys.argv[3])
|
|
|
|
if command == "check-docs":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: check-docs <doc_file>")
|
|
return 1
|
|
return check_docs(sys.argv[2])
|
|
|
|
if command == "check-doc-patterns":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: check-doc-patterns <doc_file>")
|
|
return 1
|
|
return check_doc_patterns(sys.argv[2])
|
|
|
|
if command == "validate-all":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: validate-all <directory>")
|
|
return 1
|
|
return validate_all_examples(sys.argv[2])
|
|
|
|
print(f"Unknown command: {command}")
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|