diff --git a/features/actor_config_nodes_edges.feature b/features/actor_config_nodes_edges.feature new file mode 100644 index 000000000..bf20c7744 --- /dev/null +++ b/features/actor_config_nodes_edges.feature @@ -0,0 +1,17 @@ +@tdd_issue @tdd_issue_10860 +Feature: Actor graph_descriptor exposes nodes and edges from route block + As a developer using graph actors + I want nodes and edges from the route block to appear as top-level keys in graph_descriptor + So that 'agents actor add' correctly reports node and edge counts + + Scenario: v3 graph actor with nodes and edges in route reports correct counts + Given a v3 graph actor blob with a route containing 2 nodes and 1 edge + When I parse the actor configuration from the v3 blob + Then the parsed graph_descriptor node count should be 2 + And the parsed graph_descriptor edge count should be 1 + + Scenario: v3 graph actor route with no nodes or edges defaults to empty lists + Given a v3 graph actor blob with a route containing no nodes or edges + When I parse the actor configuration from the v3 blob + Then the parsed graph_descriptor node count should be 0 + And the parsed graph_descriptor edge count should be 0 diff --git a/features/steps/actor_config_nodes_edges_steps.py b/features/steps/actor_config_nodes_edges_steps.py new file mode 100644 index 000000000..14cd839fe --- /dev/null +++ b/features/steps/actor_config_nodes_edges_steps.py @@ -0,0 +1,50 @@ +"""Step definitions for actor_config_nodes_edges.feature — regression for issue #10860.""" + +from __future__ import annotations + +from behave import given, then, when +from behave.runner import Context # type: ignore[import-untyped] + +from cleveragents.actor.config import ActorConfiguration + + +@given("a v3 graph actor blob with a route containing 2 nodes and 1 edge") +def step_graph_actor_blob_with_nodes(context: Context) -> None: + context.blob = { + "type": "graph", + "model": "openai/gpt-4", + "route": { + "nodes": ["start", "end"], + "edges": [["start", "end"]], + }, + } + + +@given("a v3 graph actor blob with a route containing no nodes or edges") +def step_graph_actor_blob_empty(context: Context) -> None: + context.blob = { + "type": "graph", + "model": "openai/gpt-4", + "route": {}, + } + + +@when("I parse the actor configuration from the v3 blob") +def step_parse_actor_config(context: Context) -> None: + context.actor_config = ActorConfiguration.from_blob(blob=context.blob) + + +@then("the parsed graph_descriptor node count should be {count:d}") +def step_check_graph_descriptor_nodes(context: Context, count: int) -> None: + gd = context.actor_config.graph_descriptor + assert gd is not None, "graph_descriptor is None" + nodes = gd.get("nodes", []) + assert len(nodes) == count, f"Expected {count} nodes, got {len(nodes)}: {nodes}" + + +@then("the parsed graph_descriptor edge count should be {count:d}") +def step_check_graph_descriptor_edges(context: Context, count: int) -> None: + gd = context.actor_config.graph_descriptor + assert gd is not None, "graph_descriptor is None" + edges = gd.get("edges", []) + assert len(edges) == count, f"Expected {count} edges, got {len(edges)}: {edges}" diff --git a/src/cleveragents/actor/config.py b/src/cleveragents/actor/config.py index 01a14f8e4..ab6dd7847 100644 --- a/src/cleveragents/actor/config.py +++ b/src/cleveragents/actor/config.py @@ -408,10 +408,14 @@ class ActorConfiguration(BaseModel): if isinstance(actor_type, str) and actor_type.lower() == "graph": route_raw = data.get("route") if isinstance(route_raw, dict): + nodes_raw = route_raw.get("nodes", []) + edges_raw = route_raw.get("edges", []) graph_descriptor = { "type": "graph", "route": route_raw, "model": model_value or "", + "nodes": nodes_raw, + "edges": edges_raw, } return provider_value or "custom", model_value, graph_descriptor, unsafe_flag diff --git a/src/cleveragents/cli/commands/actor.py b/src/cleveragents/cli/commands/actor.py index b95eb0ec1..d5643a0dc 100644 --- a/src/cleveragents/cli/commands/actor.py +++ b/src/cleveragents/cli/commands/actor.py @@ -526,10 +526,8 @@ def _print_actor( options_count = len(blob.get("options", {}) or {}) graph_descriptor = actor.graph_descriptor or {} - route = graph_descriptor.get("route", {}) or {} - - nodes_count = len(route.get("nodes", []) or []) - edges_count = len(route.get("edges", []) or []) + nodes_count = len(graph_descriptor.get("nodes", []) or []) + edges_count = len(graph_descriptor.get("edges", []) or []) config_details = ( f"[bold]Path:[/bold] {path_str}\n"