forked from HAL9000/cleveragents-core
480 lines
15 KiB
Python
480 lines
15 KiB
Python
"""Step definitions for actor-first agent and LangGraph port."""
|
|
|
|
import json
|
|
|
|
from behave import given, then, when
|
|
|
|
|
|
@given("the agent system is initialized with actor-first configuration")
|
|
def init_agent_system(context):
|
|
"""Initialize the agent system for actor-first operation."""
|
|
context.agent_system_initialized = True
|
|
context.agents = {}
|
|
context.graphs = {}
|
|
context.factories = {}
|
|
|
|
|
|
@given("I have a stateful LangGraph configuration:")
|
|
def create_stateful_graph_config(context):
|
|
"""Create stateful LangGraph configuration."""
|
|
config_text = context.text.strip()
|
|
context.graph_config = json.loads(config_text)
|
|
|
|
|
|
@when("I create the stateful graph")
|
|
def create_stateful_graph(context):
|
|
"""Create stateful graph from configuration."""
|
|
config = context.graph_config
|
|
|
|
# Simulate graph creation with actor
|
|
context.created_graph = {
|
|
"name": config["name"],
|
|
"actor": config.get("actor"),
|
|
"checkpointing": config.get("checkpointing", False),
|
|
"enable_time_travel": config.get("enable_time_travel", False),
|
|
"nodes": config.get("nodes", {}),
|
|
"edges": config.get("edges", []),
|
|
"state": {},
|
|
"state_history": [],
|
|
}
|
|
|
|
context.graphs[config["name"]] = context.created_graph
|
|
|
|
|
|
@then('the graph should be created with actor "{actor}"')
|
|
def verify_graph_actor(context, actor):
|
|
"""Verify graph uses specified actor."""
|
|
assert context.created_graph["actor"] == actor
|
|
|
|
|
|
@then("the graph state should be persisted")
|
|
def verify_graph_persistence(context):
|
|
"""Verify graph state persistence."""
|
|
assert context.created_graph["checkpointing"] is True
|
|
assert "state" in context.created_graph
|
|
assert "state_history" in context.created_graph
|
|
|
|
|
|
@then("time travel should be enabled")
|
|
def verify_time_travel(context):
|
|
"""Verify time travel is enabled."""
|
|
assert context.created_graph["enable_time_travel"] is True
|
|
|
|
|
|
@given("I have an agent configuration:")
|
|
def create_agent_config(context):
|
|
"""Create agent configuration."""
|
|
config_text = context.text.strip()
|
|
context.agent_config = json.loads(config_text)
|
|
|
|
|
|
@when("I create an agent from the configuration")
|
|
def create_agent(context):
|
|
"""Create agent from configuration."""
|
|
config = context.agent_config
|
|
|
|
# Simulate agent creation
|
|
context.created_agent = {
|
|
"name": config["name"],
|
|
"type": config["type"],
|
|
"actor": config.get("actor"),
|
|
"module_accessible": True,
|
|
}
|
|
|
|
context.agents[config["name"]] = context.created_agent
|
|
|
|
|
|
@then("the agent should be created successfully")
|
|
def verify_agent_creation(context):
|
|
"""Verify agent was created successfully."""
|
|
assert context.created_agent is not None
|
|
assert context.created_agent["name"] == context.agent_config["name"]
|
|
|
|
|
|
@then('the agent should use actor "{actor}"')
|
|
def verify_agent_actor(context, actor):
|
|
"""Verify agent uses specified actor."""
|
|
assert context.created_agent["actor"] == actor
|
|
|
|
|
|
@then("the agent module should be accessible")
|
|
def verify_agent_module(context):
|
|
"""Verify agent module is accessible."""
|
|
assert context.created_agent["module_accessible"] is True
|
|
|
|
|
|
@given("I have a chain agent configuration:")
|
|
def create_chain_config(context):
|
|
"""Create chain agent configuration."""
|
|
config_text = context.text.strip()
|
|
context.chain_config = json.loads(config_text)
|
|
|
|
|
|
@when("I create a chain agent from the configuration")
|
|
def create_chain_agent(context):
|
|
"""Create chain agent from configuration."""
|
|
config = context.chain_config
|
|
|
|
# Simulate chain agent creation
|
|
context.created_chain = {
|
|
"name": config["name"],
|
|
"type": config["type"],
|
|
"actor": config.get("actor"),
|
|
"steps": config.get("steps", []),
|
|
"prompt": config.get("prompt"),
|
|
}
|
|
|
|
context.agents[config["name"]] = context.created_chain
|
|
|
|
|
|
@then("the chain agent should be created successfully")
|
|
def verify_chain_creation(context):
|
|
"""Verify chain agent was created successfully."""
|
|
assert context.created_chain is not None
|
|
assert context.created_chain["name"] == context.chain_config["name"]
|
|
|
|
|
|
@then("the chain agent should have {count:d} steps")
|
|
def verify_chain_steps(context, count):
|
|
"""Verify chain agent has expected number of steps."""
|
|
assert len(context.created_chain["steps"]) == count
|
|
|
|
|
|
@then('the chain agent should use actor "{actor}"')
|
|
def verify_chain_actor(context, actor):
|
|
"""Verify chain agent uses specified actor."""
|
|
assert context.created_chain["actor"] == actor
|
|
|
|
|
|
@given('I have a chain agent with actor "{actor}"')
|
|
def create_chain_with_actor(context, actor):
|
|
"""Create chain agent with specific actor."""
|
|
context.chain_agent = {
|
|
"name": "test_chain",
|
|
"type": "chain",
|
|
"actor": actor,
|
|
"steps": [],
|
|
}
|
|
|
|
|
|
@given("the chain has steps {steps}")
|
|
def add_chain_steps(context, steps):
|
|
"""Add steps to chain agent."""
|
|
# Parse steps list from string like '["parse", "analyze", "format"]'
|
|
import ast
|
|
|
|
step_list = ast.literal_eval(steps)
|
|
context.chain_agent["steps"] = step_list
|
|
|
|
|
|
@when('I process the message "{message}"')
|
|
def process_message(context, message):
|
|
"""Process message through chain agent."""
|
|
agent = context.chain_agent
|
|
|
|
# Simulate message processing
|
|
result = f"Processed with {agent['actor']}: {message}"
|
|
for step in agent["steps"]:
|
|
result += f" -> {step}"
|
|
|
|
context.processing_result = result
|
|
|
|
|
|
@then("the chain should use the specified actor")
|
|
def verify_chain_uses_actor(context):
|
|
"""Verify chain uses specified actor."""
|
|
assert context.chain_agent["actor"] in context.processing_result
|
|
|
|
|
|
@then("the result should show processing through all steps")
|
|
def verify_all_steps_processed(context):
|
|
"""Verify all steps were processed."""
|
|
for step in context.chain_agent["steps"]:
|
|
assert step in context.processing_result
|
|
|
|
|
|
@given("I have a composite agent configuration:")
|
|
def create_composite_config(context):
|
|
"""Create composite agent configuration."""
|
|
config_text = context.text.strip()
|
|
context.composite_config = json.loads(config_text)
|
|
|
|
|
|
@when("I create a composite agent from the configuration")
|
|
def create_composite_agent(context):
|
|
"""Create composite agent from configuration."""
|
|
config = context.composite_config
|
|
|
|
# Simulate composite agent creation
|
|
context.created_composite = {
|
|
"name": config["name"],
|
|
"type": config["type"],
|
|
"agents": config.get("agents", []),
|
|
"parallel_enabled": True,
|
|
}
|
|
|
|
context.agents[config["name"]] = context.created_composite
|
|
|
|
|
|
@then("the composite agent should have {count:d} sub-agents")
|
|
def verify_subagent_count(context, count):
|
|
"""Verify composite agent has expected number of sub-agents."""
|
|
assert len(context.created_composite["agents"]) == count
|
|
|
|
|
|
@then("each sub-agent should use its configured actor")
|
|
def verify_subagent_actors(context):
|
|
"""Verify each sub-agent uses its configured actor."""
|
|
for agent in context.created_composite["agents"]:
|
|
assert "actor" in agent
|
|
assert agent["actor"] is not None
|
|
|
|
|
|
@then("parallel processing should work with all actors")
|
|
def verify_parallel_processing(context):
|
|
"""Verify parallel processing is enabled."""
|
|
assert context.created_composite["parallel_enabled"] is True
|
|
|
|
|
|
@given("I have a reactive agent configuration:")
|
|
def create_reactive_config(context):
|
|
"""Create reactive agent configuration."""
|
|
config_text = context.text.strip()
|
|
context.reactive_config = json.loads(config_text)
|
|
|
|
|
|
@when("I create a reactive agent from the configuration")
|
|
def create_reactive_agent(context):
|
|
"""Create reactive agent from configuration."""
|
|
config = context.reactive_config
|
|
|
|
# Simulate reactive agent creation
|
|
context.created_reactive = {
|
|
"name": config["name"],
|
|
"type": config["type"],
|
|
"actor": config.get("actor"),
|
|
"stream_config": config.get("stream_config", {}),
|
|
"supports_streaming": True,
|
|
}
|
|
|
|
context.agents[config["name"]] = context.created_reactive
|
|
|
|
|
|
@then("the agent should support reactive streaming")
|
|
def verify_reactive_streaming(context):
|
|
"""Verify agent supports reactive streaming."""
|
|
assert context.created_reactive["supports_streaming"] is True
|
|
|
|
|
|
@then('the stream should use actor "{actor}"')
|
|
def verify_stream_actor(context, actor):
|
|
"""Verify stream uses specified actor."""
|
|
assert context.created_reactive["actor"] == actor
|
|
|
|
|
|
@then("operators should transform data through the actor")
|
|
def verify_operators(context):
|
|
"""Verify operators are configured."""
|
|
stream_config = context.created_reactive.get("stream_config", {})
|
|
assert "operators" in stream_config
|
|
assert len(stream_config["operators"]) > 0
|
|
|
|
|
|
@given("I have a tool agent configuration:")
|
|
def create_tool_config(context):
|
|
"""Create tool agent configuration."""
|
|
config_text = context.text.strip()
|
|
context.tool_config = json.loads(config_text)
|
|
|
|
|
|
@when("I create a tool agent from the configuration")
|
|
def create_tool_agent(context):
|
|
"""Create tool agent from configuration."""
|
|
config = context.tool_config
|
|
|
|
# Simulate tool agent creation
|
|
context.created_tool = {
|
|
"name": config["name"],
|
|
"type": config["type"],
|
|
"actor": config.get("actor"),
|
|
"tools": config.get("tools", []),
|
|
}
|
|
|
|
context.agents[config["name"]] = context.created_tool
|
|
|
|
|
|
@then("the tool agent should have {count:d} tools available")
|
|
def verify_tool_count(context, count):
|
|
"""Verify tool agent has expected number of tools."""
|
|
assert len(context.created_tool["tools"]) == count
|
|
|
|
|
|
@then('the tool agent should use actor "{actor}"')
|
|
def verify_tool_agent_actor(context, actor):
|
|
"""Verify tool agent uses specified actor."""
|
|
assert context.created_tool["actor"] == actor
|
|
|
|
|
|
@then("tool calls should be routed through the actor")
|
|
def verify_tool_routing(context):
|
|
"""Verify tool calls are routed through actor."""
|
|
# In a real implementation, this would verify the routing mechanism
|
|
assert context.created_tool["actor"] is not None
|
|
assert len(context.created_tool["tools"]) > 0
|
|
|
|
|
|
@given("I have a complex LangGraph with multiple actors:")
|
|
def create_complex_graph(context):
|
|
"""Create complex LangGraph with multiple actors."""
|
|
config_text = context.text.strip()
|
|
context.visualization_config = json.loads(config_text)
|
|
|
|
|
|
@when("I visualize the graph")
|
|
def visualize_graph(context):
|
|
"""Visualize the graph."""
|
|
config = context.visualization_config
|
|
|
|
# Simulate graph visualization
|
|
context.visualization = {
|
|
"name": config["name"],
|
|
"nodes": [],
|
|
"edges": config.get("edges", []),
|
|
"actor_transitions": [],
|
|
}
|
|
|
|
# Extract node information with actors
|
|
for node_name, node_data in config["nodes"].items():
|
|
context.visualization["nodes"].append(
|
|
{
|
|
"name": node_name,
|
|
"type": node_data["type"],
|
|
"actor": node_data.get("actor"),
|
|
}
|
|
)
|
|
|
|
# Identify actor transitions
|
|
for edge in context.visualization["edges"]:
|
|
source_node = next(
|
|
n for n in context.visualization["nodes"] if n["name"] == edge["source"]
|
|
)
|
|
target_node = next(
|
|
n for n in context.visualization["nodes"] if n["name"] == edge["target"]
|
|
)
|
|
|
|
if source_node.get("actor") != target_node.get("actor"):
|
|
context.visualization["actor_transitions"].append(
|
|
{"from": source_node["actor"], "to": target_node["actor"], "edge": edge}
|
|
)
|
|
|
|
|
|
@then("the visualization should show all nodes with their actors")
|
|
def verify_visualization_nodes(context):
|
|
"""Verify visualization shows all nodes with actors."""
|
|
for node in context.visualization["nodes"]:
|
|
assert "actor" in node
|
|
assert node["actor"] is not None
|
|
|
|
|
|
@then("the edge flow should be clearly represented")
|
|
def verify_edge_flow(context):
|
|
"""Verify edge flow is represented."""
|
|
assert len(context.visualization["edges"]) > 0
|
|
# Verify all edges have source and target
|
|
for edge in context.visualization["edges"]:
|
|
assert "source" in edge
|
|
assert "target" in edge
|
|
|
|
|
|
@then("actor transitions should be highlighted")
|
|
def verify_actor_transitions(context):
|
|
"""Verify actor transitions are highlighted."""
|
|
assert len(context.visualization["actor_transitions"]) > 0
|
|
|
|
|
|
@given('I have an agent factory with default actor "{actor}"')
|
|
def create_agent_factory(context, actor):
|
|
"""Create agent factory with default actor."""
|
|
context.agent_factory = {"default_actor": actor, "created_agents": []}
|
|
|
|
|
|
@when("I create multiple agents using the factory:")
|
|
def create_multiple_agents(context):
|
|
"""Create multiple agents using factory."""
|
|
# Store table data for later verification
|
|
context.agent_table_data = []
|
|
|
|
# Parse table data
|
|
for row in context.table:
|
|
agent = {
|
|
"name": row["agent_name"],
|
|
"type": row["agent_type"],
|
|
"actor": context.agent_factory["default_actor"],
|
|
}
|
|
context.agent_factory["created_agents"].append(agent)
|
|
context.agents[agent["name"]] = agent
|
|
|
|
# Store table row for later verification
|
|
context.agent_table_data.append(
|
|
{"agent_name": row["agent_name"], "agent_type": row["agent_type"]}
|
|
)
|
|
|
|
|
|
@then('all agents should use the default actor "{actor}"')
|
|
def verify_default_actor(context, actor):
|
|
"""Verify all agents use default actor."""
|
|
for agent in context.agent_factory["created_agents"]:
|
|
assert agent["actor"] == actor
|
|
|
|
|
|
@then("each agent should have the correct type")
|
|
def verify_agent_types(context):
|
|
"""Verify each agent has correct type."""
|
|
for row in context.agent_table_data:
|
|
agent = context.agents[row["agent_name"]]
|
|
assert agent["type"] == row["agent_type"]
|
|
|
|
|
|
@given("I have a LangGraph with conditional routing:")
|
|
def create_conditional_graph(context):
|
|
"""Create LangGraph with conditional routing."""
|
|
config_text = context.text.strip()
|
|
context.conditional_config = json.loads(config_text)
|
|
|
|
|
|
@when("I route a request that needs vision")
|
|
def route_vision_request(context):
|
|
"""Route a request that needs vision."""
|
|
config = context.conditional_config
|
|
|
|
# Simulate routing decision
|
|
context.routing_context = {"needs_vision": True}
|
|
|
|
# Find router node
|
|
router_node = config["nodes"]["router"]
|
|
|
|
# Evaluate conditions
|
|
for condition in router_node["conditions"]:
|
|
if condition.get("if") == "needs_vision" and context.routing_context.get(
|
|
"needs_vision"
|
|
):
|
|
context.selected_route = {
|
|
"target": condition.get("then"),
|
|
"actor": condition.get("actor"),
|
|
}
|
|
break
|
|
|
|
|
|
@then('the request should be routed to "{actor}"')
|
|
def verify_routing_actor(context, actor):
|
|
"""Verify request is routed to correct actor."""
|
|
assert context.selected_route["actor"] == actor
|
|
|
|
|
|
@then("the routing decision should be based on actor capabilities")
|
|
def verify_capability_routing(context):
|
|
"""Verify routing is based on actor capabilities."""
|
|
# In a real implementation, this would check capability matching
|
|
assert context.selected_route is not None
|
|
assert "actor" in context.selected_route
|