02e51b9298
CI / build (pull_request) Successful in 34s
CI / helm (pull_request) Successful in 38s
CI / lint (pull_request) Successful in 45s
CI / typecheck (pull_request) Successful in 1m4s
CI / security (pull_request) Successful in 1m10s
CI / quality (pull_request) Successful in 1m16s
CI / push-validation (pull_request) Successful in 18s
CI / unit_tests (pull_request) Successful in 6m32s
CI / docker (pull_request) Successful in 1m37s
CI / coverage (pull_request) Successful in 13m26s
CI / integration_tests (pull_request) Successful in 23m55s
CI / status-check (pull_request) Successful in 4s
- Remove trailing whitespace from blank lines in _extract_lsp_bindings() (W293 at lines 160, 164, 167, 172, 183, 188, 203) - Simplify over-long line 180 (E501): auto_detect=node.lsp_binding.auto - Add Behave scenario verifying NodeLspBinding typed field populates CompilationMetadata.lsp_bindings (features/actor_lsp_binding_field.feature) - Add corresponding @given step using NodeLspBinding in actor_compiler_steps.py - Add Robot Framework regression test case and lsp-binding-field helper command confirming node.lsp_binding is read by compile_actor() - Update CHANGELOG.md and CONTRIBUTORS.md ISSUES CLOSED: #1432
200 lines
6.7 KiB
Python
200 lines
6.7 KiB
Python
"""Robot Framework helper for actor compiler smoke tests.
|
|
|
|
Provides a CLI interface for Robot to invoke the actor compiler on
|
|
YAML-defined GRAPH actors and inspect compilation metadata.
|
|
|
|
Usage:
|
|
python robot/helper_actor_compiler.py compile <yaml_file>
|
|
python robot/helper_actor_compiler.py compile-fail <yaml_file>
|
|
python robot/helper_actor_compiler.py metadata <yaml_file>
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
from cleveragents.actor.compiler import compile_actor # noqa: E402
|
|
from cleveragents.actor.schema import ActorConfigSchema # noqa: E402
|
|
|
|
|
|
def main() -> int:
|
|
"""Entry point called by Robot Framework ``Run Process``."""
|
|
if len(sys.argv) < 3:
|
|
print("Usage: helper_actor_compiler.py <compile|compile-fail|metadata> <file>")
|
|
return 1
|
|
|
|
command = sys.argv[1]
|
|
yaml_path = sys.argv[2]
|
|
|
|
if command == "compile":
|
|
try:
|
|
config = ActorConfigSchema.from_yaml_file(yaml_path)
|
|
compiled = compile_actor(config)
|
|
print(f"actor-compiler-ok: {compiled.name}")
|
|
print(f"nodes: {len(compiled.nodes)}")
|
|
print(f"edges: {len(compiled.edges)}")
|
|
print(f"entry: {compiled.entry_point}")
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"actor-compiler-fail: {exc}")
|
|
return 1
|
|
|
|
if command == "compile-fail":
|
|
try:
|
|
config = ActorConfigSchema.from_yaml_file(yaml_path)
|
|
compile_actor(config)
|
|
print("actor-compiler-unexpected-success")
|
|
return 1
|
|
except Exception as exc:
|
|
print(f"actor-compiler-expected-fail: {exc}")
|
|
return 0
|
|
|
|
if command == "metadata":
|
|
try:
|
|
config = ActorConfigSchema.from_yaml_file(yaml_path)
|
|
compiled = compile_actor(config)
|
|
meta = compiled.metadata.model_dump(mode="json")
|
|
print(f"actor-compiler-metadata: {json.dumps(meta)}")
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"actor-compiler-fail: {exc}")
|
|
return 1
|
|
|
|
if command == "cycle-detect":
|
|
# Test cross-actor cycle detection using actor_ref top-level field.
|
|
# Creates two mutually-referencing actors and verifies SubgraphCycleError
|
|
# is raised, confirming the fix for issue #1431.
|
|
from cleveragents.actor.compiler import SubgraphCycleError
|
|
from cleveragents.actor.schema import (
|
|
ActorType,
|
|
EdgeDefinition,
|
|
NodeDefinition,
|
|
NodeType,
|
|
RouteDefinition,
|
|
)
|
|
|
|
def _make_actor(
|
|
name: str, subgraph_ref: str | None = None
|
|
) -> ActorConfigSchema:
|
|
if subgraph_ref is not None:
|
|
nodes = [
|
|
NodeDefinition(
|
|
id="start",
|
|
type=NodeType.AGENT,
|
|
name="Start",
|
|
description="Start",
|
|
config={"agent": "default"},
|
|
),
|
|
NodeDefinition(
|
|
id="sub",
|
|
type=NodeType.SUBGRAPH,
|
|
name="Sub",
|
|
description="Subgraph",
|
|
config={},
|
|
actor_ref=subgraph_ref,
|
|
),
|
|
]
|
|
edges = [EdgeDefinition(from_node="start", to_node="sub")]
|
|
entry, exits = "start", ["sub"]
|
|
else:
|
|
nodes = [
|
|
NodeDefinition(
|
|
id="leaf",
|
|
type=NodeType.AGENT,
|
|
name="Leaf",
|
|
description="Leaf",
|
|
config={"agent": "default"},
|
|
)
|
|
]
|
|
edges = []
|
|
entry, exits = "leaf", ["leaf"]
|
|
route = RouteDefinition(
|
|
nodes=nodes, edges=edges, entry_node=entry, exit_nodes=exits
|
|
)
|
|
return ActorConfigSchema(
|
|
name=name,
|
|
type=ActorType.GRAPH,
|
|
description=f"Test actor {name}",
|
|
model="gpt-4",
|
|
route=route,
|
|
)
|
|
|
|
actor_a = _make_actor("test/actor-a", subgraph_ref="test/actor-b")
|
|
actor_b = _make_actor("test/actor-b", subgraph_ref="test/actor-a")
|
|
registry = {"test/actor-a": actor_a, "test/actor-b": actor_b}
|
|
|
|
try:
|
|
compile_actor(actor_a, actor_resolver=registry.get)
|
|
print(
|
|
"actor-compiler-cycle-not-detected: FAIL — expected SubgraphCycleError"
|
|
)
|
|
return 1
|
|
except SubgraphCycleError as exc:
|
|
print(f"actor-compiler-cycle-detected: {exc}")
|
|
return 0
|
|
except Exception as exc:
|
|
print(f"actor-compiler-unexpected-error: {exc}")
|
|
return 1
|
|
|
|
if command == "lsp-binding-field":
|
|
# Regression test for issue #1432: _extract_lsp_bindings() must read
|
|
# from node.lsp_binding (NodeLspBinding typed field), not only config dict.
|
|
from cleveragents.actor.schema import (
|
|
ActorType,
|
|
NodeDefinition,
|
|
NodeLspBinding,
|
|
NodeType,
|
|
RouteDefinition,
|
|
)
|
|
|
|
node = NodeDefinition(
|
|
id="coder",
|
|
type=NodeType.AGENT,
|
|
name="Coder",
|
|
description="Code writing node with typed LSP binding",
|
|
config={"agent": "coder_agent"},
|
|
lsp_binding=NodeLspBinding(
|
|
server="local/pyright",
|
|
languages=["python"],
|
|
auto=False,
|
|
),
|
|
)
|
|
route = RouteDefinition(
|
|
nodes=[node],
|
|
edges=[],
|
|
entry_node="coder",
|
|
exit_nodes=["coder"],
|
|
)
|
|
config = ActorConfigSchema(
|
|
name="workflows/lsp_typed",
|
|
type=ActorType.GRAPH,
|
|
description="Test actor with typed lsp_binding field",
|
|
model="gpt-4",
|
|
route=route,
|
|
)
|
|
try:
|
|
compiled = compile_actor(config)
|
|
bindings = compiled.metadata.lsp_bindings
|
|
if len(bindings) == 1 and bindings[0].lsp_server_name == "local/pyright":
|
|
print("actor-compiler-lsp-binding-ok")
|
|
print(f"lsp-server: {bindings[0].lsp_server_name}")
|
|
return 0
|
|
print(f"actor-compiler-lsp-binding-fail: got {bindings}")
|
|
return 1
|
|
except Exception as exc:
|
|
print(f"actor-compiler-fail: {exc}")
|
|
return 1
|
|
|
|
print(f"Unknown command: {command}")
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|