Compare commits

...

4 Commits

Author SHA1 Message Date
Timothy 960b7ab3b1 fix: lint and tool test 2026-03-08 17:17:37 -07:00
Richard Tang 28df1bd2dc fix: remove unused code 2026-03-07 09:09:40 -08:00
Richard Tang bb5962b771 chore: fix ruff lint 2026-03-07 07:04:43 -08:00
Richard Tang 6a0024943c feat: add name mode for simplest output 2026-03-07 06:56:16 -08:00
3 changed files with 116 additions and 1 deletions
+11
View File
@@ -761,4 +761,15 @@ class GraphSpec(BaseModel):
"GCU nodes must be declared as subagents of a parent node."
)
# All sub_agents references must point to registered nodes
all_node_ids = {n.id for n in self.nodes}
for node in self.nodes:
for sa_id in node.sub_agents or []:
if sa_id not in all_node_ids:
errors.append(
f"Node '{node.id}' references sub_agent '{sa_id}' "
"which is not registered in the nodes list. "
"Ensure the sub_agent node is included in the agent's nodes."
)
return {"errors": errors, "warnings": warnings}
@@ -0,0 +1,104 @@
"""
Tests for sub_agents reference validation.
Validates that all node IDs listed in a node's sub_agents field
are actually registered in the graph's nodes list.
"""
from framework.graph.edge import GraphSpec
from framework.graph.node import NodeSpec
class TestSubAgentRegistrationValidation:
"""sub_agents references to unregistered nodes must be rejected."""
def test_sub_agent_not_registered_fails(self):
"""A node referencing a sub_agent that isn't in the nodes list -> error."""
graph = GraphSpec(
id="g1",
goal_id="goal1",
entry_node="main",
terminal_nodes=["main"],
nodes=[
NodeSpec(
id="main",
name="Main",
description="Main node",
sub_agents=["missing_gcu"],
),
],
edges=[],
)
errors = graph.validate()["errors"]
sa_errors = [e for e in errors if "not registered" in e]
assert len(sa_errors) == 1
assert "'missing_gcu'" in sa_errors[0]
assert "'main'" in sa_errors[0]
def test_sub_agent_registered_passes(self):
"""A node referencing a sub_agent that exists in nodes -> no error."""
graph = GraphSpec(
id="g1",
goal_id="goal1",
entry_node="main",
terminal_nodes=["main"],
nodes=[
NodeSpec(
id="main",
name="Main",
description="Main node",
sub_agents=["helper"],
),
NodeSpec(
id="helper",
name="Helper",
description="Helper GCU node",
node_type="gcu",
),
],
edges=[],
)
errors = graph.validate()["errors"]
sa_errors = [e for e in errors if "not registered" in e]
assert len(sa_errors) == 0
def test_multiple_unregistered_sub_agents(self):
"""Multiple missing sub_agents -> one error per missing reference."""
graph = GraphSpec(
id="g1",
goal_id="goal1",
entry_node="main",
terminal_nodes=["main"],
nodes=[
NodeSpec(
id="main",
name="Main",
description="Main node",
sub_agents=["missing_a", "missing_b"],
),
],
edges=[],
)
errors = graph.validate()["errors"]
sa_errors = [e for e in errors if "not registered" in e]
assert len(sa_errors) == 2
def test_no_sub_agents_passes(self):
"""A node with no sub_agents -> no error from this rule."""
graph = GraphSpec(
id="g1",
goal_id="goal1",
entry_node="main",
terminal_nodes=["main"],
nodes=[
NodeSpec(id="main", name="Main", description="Main node"),
],
edges=[],
)
errors = graph.validate()["errors"]
sa_errors = [e for e in errors if "not registered" in e]
assert len(sa_errors) == 0
+1 -1
View File
@@ -114,7 +114,7 @@ def test_list_agent_tools_groups_by_provider_and_keeps_uncredentialed(monkeypatc
google_tools = {t["name"] for t in providers["google"]["tools"]}
assert "gmail_list_messages" in google_tools
assert "calendar_list_events" in google_tools
assert "send_email" in google_tools
assert "send_email" not in google_tools # multi-provider tool, only in resend
assert providers["google"]["authorization"]
resend_tools = {t["name"] for t in providers["resend"]["tools"]}