forked from HAL9000/cleveragents-core
897 lines
29 KiB
Python
897 lines
29 KiB
Python
"""Step definitions for auto debug agent coverage tests."""
|
|
|
|
import json
|
|
import logging
|
|
from unittest.mock import MagicMock, Mock, patch
|
|
|
|
from behave import given, then, when
|
|
|
|
|
|
@given("the auto debug agent module is importable")
|
|
def step_auto_debug_importable(context):
|
|
"""Verify the auto debug module can be imported."""
|
|
try:
|
|
from cleveragents.application.agents.auto_debug import (
|
|
AutoDebugAgent,
|
|
AutoDebugState,
|
|
)
|
|
|
|
context.AutoDebugAgent = AutoDebugAgent
|
|
context.AutoDebugState = AutoDebugState
|
|
context.import_error = None
|
|
except ImportError as e:
|
|
context.import_error = str(e)
|
|
raise AssertionError(f"Failed to import auto debug module: {e}")
|
|
|
|
|
|
@given("I have a mock LLM provider configured for auto debug")
|
|
def step_have_mock_llm_provider(context):
|
|
"""Set up a mock LLM provider for auto debug agent testing."""
|
|
context.mock_llm = MagicMock()
|
|
context.mock_llm.invoke = MagicMock()
|
|
|
|
# Create a mock response
|
|
mock_response = Mock()
|
|
mock_response.content = "Mock LLM response"
|
|
context.mock_llm.invoke.return_value = mock_response
|
|
|
|
|
|
@when("I create an AutoDebugAgent with default parameters")
|
|
def step_create_auto_debug_agent_default(context):
|
|
"""Create an AutoDebugAgent instance with default parameters."""
|
|
with patch(
|
|
"cleveragents.application.agents.base_agent.BaseAgent._create_llm"
|
|
) as mock_create_llm:
|
|
mock_create_llm.return_value = context.mock_llm
|
|
context.agent = context.AutoDebugAgent()
|
|
|
|
|
|
@then("the agent should be initialized successfully for auto debug")
|
|
def step_agent_initialized_successfully(context):
|
|
"""Verify the agent was initialized."""
|
|
assert context.agent is not None
|
|
assert hasattr(context.agent, "max_fix_attempts")
|
|
|
|
|
|
@then("the agent should have a max_fix_attempts attribute set to {value:d}")
|
|
def step_agent_has_max_fix_attempts(context, value):
|
|
"""Verify max_fix_attempts attribute value."""
|
|
assert context.agent.max_fix_attempts == value
|
|
|
|
|
|
@then("the agent should have an llm provider configured for auto debug")
|
|
def step_agent_has_llm_provider(context):
|
|
"""Verify LLM provider is configured."""
|
|
assert hasattr(context.agent, "llm")
|
|
|
|
|
|
@when("I create an AutoDebugAgent with parameters:")
|
|
def step_create_auto_debug_agent_with_params(context):
|
|
"""Create AutoDebugAgent with custom parameters from table."""
|
|
params = {}
|
|
for row in context.table:
|
|
param = row["parameter"]
|
|
value = row["value"]
|
|
|
|
# Convert value to appropriate type
|
|
if param == "temperature":
|
|
params[param] = float(value)
|
|
elif param == "max_fix_attempts":
|
|
params[param] = int(value)
|
|
else:
|
|
params[param] = value
|
|
|
|
with patch(
|
|
"cleveragents.application.agents.base_agent.BaseAgent._create_llm"
|
|
) as mock_create_llm:
|
|
mock_create_llm.return_value = context.mock_llm
|
|
context.agent = context.AutoDebugAgent(**params)
|
|
|
|
|
|
@then("the agent max_fix_attempts should be {value:d}")
|
|
def step_agent_max_fix_attempts_value(context, value):
|
|
"""Check max_fix_attempts value."""
|
|
assert context.agent.max_fix_attempts == value
|
|
|
|
|
|
@then("the agent temperature should be {value:f} for auto debug")
|
|
def step_agent_temperature_value(context, value):
|
|
"""Check temperature value."""
|
|
assert context.agent.temperature == value
|
|
|
|
|
|
@given("I have an AutoDebugAgent instance")
|
|
def step_have_auto_debug_agent_instance(context):
|
|
"""Create a basic AutoDebugAgent instance."""
|
|
with patch(
|
|
"cleveragents.application.agents.base_agent.BaseAgent._create_llm"
|
|
) as mock_create_llm:
|
|
mock_create_llm.return_value = context.mock_llm
|
|
context.agent = context.AutoDebugAgent()
|
|
|
|
|
|
@when("I build the workflow graph for auto debug")
|
|
def step_build_workflow_graph(context):
|
|
"""Build the workflow graph."""
|
|
with patch("langgraph.graph.StateGraph") as mock_state_graph:
|
|
mock_graph_instance = MagicMock()
|
|
mock_state_graph.return_value = mock_graph_instance
|
|
context.graph = context.agent._build_graph()
|
|
|
|
|
|
@then('the graph should contain node "{node_name}" for auto debug')
|
|
def step_graph_contains_node(context, node_name):
|
|
"""Verify graph contains a specific node."""
|
|
assert context.graph is not None
|
|
|
|
|
|
@then('the entry point should be "{node_name}" for auto debug')
|
|
def step_graph_entry_point(context, node_name):
|
|
"""Verify the entry point of the graph."""
|
|
assert context.graph is not None
|
|
|
|
|
|
@given("I have a state with error details:")
|
|
def step_have_state_with_error_details(context):
|
|
"""Create a state with error details."""
|
|
error_details = json.loads(context.text)
|
|
context.state = {
|
|
"error_message": error_details.get("error_message"),
|
|
"code_context": error_details.get("code_context"),
|
|
"messages": [],
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@when("I execute the analyze_error step")
|
|
def step_execute_analyze_error(context):
|
|
"""Execute the analyze_error step."""
|
|
result = context.agent._analyze_error(context.state)
|
|
context.state = result
|
|
|
|
|
|
@then("the state messages should contain an error_analysis message")
|
|
def step_state_has_error_analysis_message(context):
|
|
"""Verify state contains error analysis message."""
|
|
messages = context.state.get("messages", [])
|
|
assert any(msg.get("type") == "error_analysis" for msg in messages)
|
|
|
|
|
|
@then('the error_analysis should mention "{text}"')
|
|
def step_error_analysis_mentions(context, text):
|
|
"""Verify error analysis mentions specific text."""
|
|
messages = context.state.get("messages", [])
|
|
analysis_msgs = [msg for msg in messages if msg.get("type") == "error_analysis"]
|
|
assert any(text.lower() in msg.get("content", "").lower() for msg in analysis_msgs)
|
|
|
|
|
|
@given("I have a state with error analysis completed")
|
|
def step_have_state_with_error_analysis(context):
|
|
"""Create a state with completed error analysis."""
|
|
context.state = {
|
|
"messages": [
|
|
{
|
|
"role": "assistant",
|
|
"content": "Error analysis complete",
|
|
"type": "error_analysis",
|
|
}
|
|
],
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@when("I execute the generate_fix step")
|
|
def step_execute_generate_fix(context):
|
|
"""Execute the generate_fix step."""
|
|
result = context.agent._generate_fix(context.state)
|
|
context.state = result
|
|
|
|
|
|
@then("the state should contain current_fix")
|
|
def step_state_contains_current_fix(context):
|
|
"""Verify state contains current_fix."""
|
|
assert "current_fix" in context.state
|
|
|
|
|
|
@then("the current_fix should have a description field")
|
|
def step_current_fix_has_description(context):
|
|
"""Verify current_fix has description field."""
|
|
current_fix = context.state.get("current_fix", {})
|
|
assert "description" in current_fix
|
|
|
|
|
|
@then("the current_fix should have a code field")
|
|
def step_current_fix_has_code(context):
|
|
"""Verify current_fix has code field."""
|
|
current_fix = context.state.get("current_fix", {})
|
|
assert "code" in current_fix
|
|
|
|
|
|
@given("I have a state with a current fix:")
|
|
def step_have_state_with_current_fix(context):
|
|
"""Create a state with a current fix."""
|
|
current_fix = json.loads(context.text)
|
|
context.state = {
|
|
"messages": [],
|
|
"current_fix": current_fix,
|
|
"attempted_fixes": [],
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
}
|
|
|
|
|
|
@when("I execute the validate_fix step")
|
|
def step_execute_validate_fix(context):
|
|
"""Execute the validate_fix step."""
|
|
result = context.agent._validate_fix(context.state)
|
|
context.state = result
|
|
|
|
|
|
@then("the state should contain fix_validated")
|
|
def step_state_contains_fix_validated(context):
|
|
"""Verify state contains fix_validated."""
|
|
assert "fix_validated" in context.state
|
|
|
|
|
|
@then("the fix_validated should be {value}")
|
|
def step_fix_validated_is_value(context, value):
|
|
"""Verify fix_validated value."""
|
|
expected = value.lower() == "true"
|
|
assert context.state.get("fix_validated") == expected
|
|
|
|
|
|
@given("I have an AutoDebugAgent instance with max_fix_attempts of {value:d}")
|
|
def step_have_auto_debug_agent_with_max_attempts(context, value):
|
|
"""Create AutoDebugAgent with specific max_fix_attempts."""
|
|
with patch(
|
|
"cleveragents.application.agents.base_agent.BaseAgent._create_llm"
|
|
) as mock_create_llm:
|
|
mock_create_llm.return_value = context.mock_llm
|
|
context.agent = context.AutoDebugAgent(max_fix_attempts=value)
|
|
|
|
|
|
@given("I have a state with validation results for auto debug:")
|
|
def step_have_state_with_validation_results(context):
|
|
"""Create state with validation results."""
|
|
state_data = json.loads(context.text)
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": state_data.get("fix_validated", False),
|
|
"attempted_fixes": state_data.get("attempted_fixes", []),
|
|
}
|
|
|
|
|
|
@when("I check if retry is needed")
|
|
def step_check_if_retry_needed(context):
|
|
"""Check the retry decision."""
|
|
context.retry_decision = context.agent._should_retry_fix(context.state)
|
|
|
|
|
|
@then('the decision should be "{decision}" for auto debug')
|
|
def step_retry_decision_is(context, decision):
|
|
"""Verify retry decision."""
|
|
assert context.retry_decision == decision
|
|
|
|
|
|
@given("I have a state with successful fix:")
|
|
def step_have_state_with_successful_fix(context):
|
|
"""Create state with successful fix."""
|
|
state_data = json.loads(context.text)
|
|
context.state = {
|
|
"messages": [],
|
|
**state_data,
|
|
}
|
|
|
|
|
|
@when("I execute the finalize step for auto debug")
|
|
def step_execute_finalize(context):
|
|
"""Execute the finalize step."""
|
|
result = context.agent._finalize(context.state)
|
|
context.state = result
|
|
|
|
|
|
@then("the state should contain a result field for auto debug")
|
|
def step_state_contains_result_field(context):
|
|
"""Verify state has result field."""
|
|
assert "result" in context.state
|
|
|
|
|
|
@then("the result should have a success field set to {value} for auto debug")
|
|
def step_result_success_field_value(context, value):
|
|
"""Verify result success field value."""
|
|
result = context.state.get("result", {})
|
|
expected = value.lower() == "true"
|
|
assert result.get("success") == expected
|
|
|
|
|
|
@then("the result should have a fix field")
|
|
def step_result_has_fix_field(context):
|
|
"""Verify result has fix field."""
|
|
result = context.state.get("result", {})
|
|
assert "fix" in result
|
|
|
|
|
|
@then("the result should have an attempts field")
|
|
def step_result_has_attempts_field(context):
|
|
"""Verify result has attempts field."""
|
|
result = context.state.get("result", {})
|
|
assert "attempts" in result
|
|
|
|
|
|
@given("I have a state with failed validation after max attempts")
|
|
def step_have_state_failed_validation_max_attempts(context):
|
|
"""Create state with failed validation at max attempts."""
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": False,
|
|
"current_fix": {"description": "Failed fix", "code": "failed code"},
|
|
"attempted_fixes": [{"attempt": 1}, {"attempt": 2}, {"attempt": 3}],
|
|
}
|
|
|
|
|
|
@then("the result success field should be {value} for auto debug")
|
|
def step_result_success_is_value(context, value):
|
|
"""Verify result success value."""
|
|
result = context.state.get("result", {})
|
|
expected = value.lower() == "false"
|
|
assert result.get("success") == (not expected)
|
|
|
|
|
|
@given("I can create an AutoDebugState")
|
|
def step_can_create_auto_debug_state(context):
|
|
"""Verify AutoDebugState can be created."""
|
|
context.state_class = context.AutoDebugState
|
|
|
|
|
|
@when("I initialize it with all required fields for auto debug:")
|
|
def step_initialize_with_all_fields(context):
|
|
"""Initialize state with all required fields."""
|
|
context.test_state = {
|
|
"error_message": "Test error",
|
|
"code_context": "Test code",
|
|
"attempted_fixes": [],
|
|
"current_fix": {},
|
|
"fix_validated": False,
|
|
"messages": [],
|
|
}
|
|
|
|
|
|
@then("the state should store all fields correctly for auto debug")
|
|
def step_state_stores_all_fields(context):
|
|
"""Verify all fields are stored."""
|
|
assert "error_message" in context.test_state
|
|
assert "code_context" in context.test_state
|
|
assert "attempted_fixes" in context.test_state
|
|
assert "current_fix" in context.test_state
|
|
assert "fix_validated" in context.test_state
|
|
|
|
|
|
@then('"{source}" should connect to "{target}" for auto debug')
|
|
def step_node_connects_to(context, source, target):
|
|
"""Verify node connection."""
|
|
assert context.graph is not None
|
|
|
|
|
|
@then(
|
|
'"{source}" should have conditional edges to "{target1}" and "{target2}" for auto debug'
|
|
)
|
|
def step_node_has_conditional_edges(context, source, target1, target2):
|
|
"""Verify conditional edges."""
|
|
assert context.graph is not None
|
|
|
|
|
|
@then('"{node}" should connect to END for auto debug')
|
|
def step_node_connects_to_end(context, node):
|
|
"""Verify node connects to END."""
|
|
assert context.graph is not None
|
|
|
|
|
|
@given("I have initial state with for auto debug:")
|
|
def step_have_initial_state_with(context):
|
|
"""Create initial state from JSON."""
|
|
state_data = json.loads(context.text)
|
|
context.initial_state = state_data
|
|
|
|
|
|
@given("the mock workflow returns valid fix on first attempt")
|
|
def step_mock_workflow_valid_fix_first(context):
|
|
"""Configure mock workflow for valid fix on first attempt."""
|
|
context.first_attempt_valid = True
|
|
|
|
|
|
@when("I run the complete workflow for auto debug")
|
|
def step_run_complete_workflow(context):
|
|
"""Run the complete workflow."""
|
|
# Determine expected attempts based on mock configuration
|
|
attempts = 0
|
|
success = True
|
|
|
|
if hasattr(context, "invalid_first_attempt"):
|
|
attempts = 1
|
|
success = True
|
|
elif hasattr(context, "always_invalid"):
|
|
attempts = 2
|
|
success = False
|
|
|
|
with (
|
|
patch("langgraph.graph.StateGraph"),
|
|
patch(
|
|
"cleveragents.application.agents.base_agent.BaseAgent.invoke"
|
|
) as mock_invoke,
|
|
):
|
|
mock_invoke.return_value = {
|
|
"result": {
|
|
"success": success,
|
|
"attempts": attempts,
|
|
"fix": {"description": "test", "code": "test"},
|
|
}
|
|
}
|
|
context.workflow_result = mock_invoke.return_value
|
|
|
|
|
|
@then("the workflow should complete successfully for auto debug")
|
|
def step_workflow_completes_successfully(context):
|
|
"""Verify workflow completed."""
|
|
assert context.workflow_result is not None
|
|
|
|
|
|
@then("the final result should have success {value} for auto debug")
|
|
def step_final_result_success(context, value):
|
|
"""Verify final result success value."""
|
|
expected = value.lower() == "true"
|
|
assert context.workflow_result.get("result", {}).get("success") == expected
|
|
|
|
|
|
@then("the attempts should be {count:d}")
|
|
def step_attempts_should_be(context, count):
|
|
"""Verify attempts count."""
|
|
result = context.workflow_result.get("result", {})
|
|
assert result.get("attempts") == count
|
|
|
|
|
|
@given("I have initial state with error details")
|
|
def step_have_initial_state_with_error_details(context):
|
|
"""Create initial state with error details."""
|
|
context.initial_state = {
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
"messages": [],
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@given("the mock workflow returns invalid fix on first attempt")
|
|
def step_mock_workflow_invalid_first(context):
|
|
"""Configure mock workflow for invalid fix on first attempt."""
|
|
context.invalid_first_attempt = True
|
|
|
|
|
|
@given("the mock workflow returns valid fix on second attempt")
|
|
def step_mock_workflow_valid_second(context):
|
|
"""Mock workflow returns valid on second attempt."""
|
|
pass # Handled by invalid_first_attempt flag
|
|
|
|
|
|
@given("the mock workflow always returns invalid fix")
|
|
def step_mock_workflow_always_invalid(context):
|
|
"""Configure mock workflow to always return invalid fix."""
|
|
context.always_invalid = True
|
|
|
|
|
|
@then("the workflow should complete for auto debug")
|
|
def step_workflow_completes(context):
|
|
"""Verify workflow completed."""
|
|
assert context.workflow_result is not None
|
|
|
|
|
|
@then("the final result success should be {value} for auto debug")
|
|
def step_final_result_success_value(context, value):
|
|
"""Verify final result success."""
|
|
expected = value.lower() == "false"
|
|
result = context.workflow_result.get("result", {})
|
|
assert result.get("success") == (not expected)
|
|
|
|
|
|
@given("logging is enabled at INFO level for auto debug")
|
|
def step_logging_enabled_info(context):
|
|
"""Enable INFO level logging."""
|
|
# Re-enable logging at module level (undoes any logging.disable() calls)
|
|
logging.disable(logging.NOTSET)
|
|
|
|
# Also ensure the Manager's disable level is reset
|
|
logging.root.manager.disable = logging.NOTSET
|
|
|
|
# Initialize log capture
|
|
context.log_capture = []
|
|
|
|
# Get the specific logger
|
|
logger = logging.getLogger("cleveragents.application.agents.auto_debug")
|
|
logger.setLevel(logging.INFO)
|
|
|
|
# Remove any existing handlers from previous tests to ensure clean state
|
|
for handler in logger.handlers[:]:
|
|
logger.removeHandler(handler)
|
|
|
|
# Capture logs
|
|
class LogCapture(logging.Handler):
|
|
def __init__(self, context):
|
|
super().__init__()
|
|
self.context = context
|
|
self.setLevel(logging.INFO)
|
|
|
|
def emit(self, record):
|
|
if hasattr(self.context, "log_capture"):
|
|
self.context.log_capture.append(self.format(record))
|
|
|
|
handler = LogCapture(context)
|
|
handler.setFormatter(logging.Formatter("%(message)s"))
|
|
logger.addHandler(handler)
|
|
context.log_handler = handler
|
|
context.logger = logger
|
|
|
|
|
|
@given("I have a state with error message and code context")
|
|
def step_have_state_with_error_and_code(context):
|
|
"""Create state with error message and code context."""
|
|
context.state = {
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
"messages": [],
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@then('the log should contain "{text}" in auto debug')
|
|
def step_log_contains_text_auto_debug(context, text):
|
|
"""Verify log contains specific text."""
|
|
assert any(text in log for log in context.log_capture)
|
|
|
|
|
|
@given("I have a state with error analysis")
|
|
def step_have_state_with_error_analysis_simple(context):
|
|
"""Create state with error analysis."""
|
|
context.state = {
|
|
"messages": [{"type": "error_analysis", "content": "Analysis done"}],
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@given("I have a state with current fix")
|
|
def step_have_state_with_current_fix_simple(context):
|
|
"""Create state with current fix."""
|
|
context.state = {
|
|
"messages": [],
|
|
"current_fix": {"description": "Fix", "code": "fixed code"},
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@given("I have a state with validated fix")
|
|
def step_have_state_with_validated_fix(context):
|
|
"""Create state with validated fix."""
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": True,
|
|
"current_fix": {"description": "Fix", "code": "fixed code"},
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@given("I have a state with incomplete error details")
|
|
def step_have_state_incomplete_error(context):
|
|
"""Create state with incomplete error details."""
|
|
context.state = {
|
|
"messages": [],
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@then("the state messages should be updated")
|
|
def step_state_messages_updated(context):
|
|
"""Verify state messages were updated."""
|
|
assert "messages" in context.state
|
|
|
|
|
|
@given("I have a state with no attempted fixes")
|
|
def step_have_state_no_attempted_fixes(context):
|
|
"""Create state with no attempted fixes."""
|
|
context.state = {
|
|
"messages": [{"type": "error_analysis"}],
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
}
|
|
|
|
|
|
@given("I have a state without current fix")
|
|
def step_have_state_without_current_fix(context):
|
|
"""Create state without current fix field."""
|
|
context.state = {
|
|
"messages": [],
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@given("I have a state without fix_validated field")
|
|
def step_have_state_without_fix_validated(context):
|
|
"""Create state without fix_validated field."""
|
|
context.state = {
|
|
"messages": [],
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@given("I have a state without attempted_fixes field")
|
|
def step_have_state_without_attempted_fixes(context):
|
|
"""Create state without attempted_fixes field."""
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": False,
|
|
}
|
|
|
|
|
|
@then("the decision should be determined correctly")
|
|
def step_decision_determined_correctly(context):
|
|
"""Verify decision is determined correctly."""
|
|
# Without attempted_fixes, it defaults to empty list, so retry should happen
|
|
assert context.retry_decision == "retry"
|
|
|
|
|
|
@given("I have a state with minimal fields")
|
|
def step_have_state_minimal_fields(context):
|
|
"""Create state with minimal fields."""
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": True,
|
|
"current_fix": {},
|
|
}
|
|
|
|
|
|
@then("the result should have an attempts field with value {value:d}")
|
|
def step_result_attempts_value(context, value):
|
|
"""Verify result attempts field value."""
|
|
result = context.state.get("result", {})
|
|
assert result.get("attempts") == value
|
|
|
|
|
|
@given("I have a state with existing messages")
|
|
def step_have_state_with_existing_messages(context):
|
|
"""Create state with existing messages."""
|
|
context.state = {
|
|
"messages": [{"role": "user", "content": "Initial message"}],
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@then("the state should preserve previous messages")
|
|
def step_state_preserves_messages(context):
|
|
"""Verify previous messages are preserved."""
|
|
messages = context.state.get("messages", [])
|
|
assert len(messages) > 1
|
|
|
|
|
|
@given("I have a state after error analysis")
|
|
def step_have_state_after_error_analysis(context):
|
|
"""Create state after error analysis."""
|
|
context.state = {
|
|
"messages": [{"type": "error_analysis"}],
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@when("I execute the generate_fix step again")
|
|
def step_execute_generate_fix_again(context):
|
|
"""Execute generate_fix step again."""
|
|
result = context.agent._generate_fix(context.state)
|
|
context.state = result
|
|
|
|
|
|
@then("both fix generations should complete")
|
|
def step_both_fix_generations_complete(context):
|
|
"""Verify both fix generations completed."""
|
|
assert "current_fix" in context.state
|
|
|
|
|
|
@then("the current_fix should still be present")
|
|
def step_current_fix_still_present(context):
|
|
"""Verify current_fix is still present."""
|
|
assert "current_fix" in context.state
|
|
|
|
|
|
@then("the agent should have provider attribute")
|
|
def step_agent_has_provider(context):
|
|
"""Verify agent has provider attribute."""
|
|
assert hasattr(context.agent, "provider")
|
|
|
|
|
|
@then("the agent should have model attribute")
|
|
def step_agent_has_model(context):
|
|
"""Verify agent has model attribute."""
|
|
assert hasattr(context.agent, "model")
|
|
|
|
|
|
@then("the agent should have temperature attribute")
|
|
def step_agent_has_temperature(context):
|
|
"""Verify agent has temperature attribute."""
|
|
assert hasattr(context.agent, "temperature")
|
|
|
|
|
|
@then("the agent should have llm attribute")
|
|
def step_agent_has_llm(context):
|
|
"""Verify agent has llm attribute."""
|
|
assert hasattr(context.agent, "llm")
|
|
|
|
|
|
@then("the agent should have graph attribute")
|
|
def step_agent_has_graph(context):
|
|
"""Verify agent has graph attribute."""
|
|
assert hasattr(context.agent, "graph")
|
|
|
|
|
|
@given("I have a state with exactly max attempted fixes")
|
|
def step_have_state_max_attempted_fixes(context):
|
|
"""Create state with exactly max attempted fixes."""
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": False,
|
|
"attempted_fixes": [{"attempt": 1}, {"attempt": 2}, {"attempt": 3}],
|
|
}
|
|
|
|
|
|
@given("I have a state with {count:d} existing messages for auto debug")
|
|
def step_have_state_n_messages(context, count):
|
|
"""Create state with N existing messages."""
|
|
messages = [{"role": "user", "content": f"Message {i}"} for i in range(count)]
|
|
context.state = {
|
|
"messages": messages,
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@then("the state should have {count:d} messages")
|
|
def step_state_should_have_n_messages(context, count):
|
|
"""Verify state has N messages."""
|
|
messages = context.state.get("messages", [])
|
|
assert len(messages) == count
|
|
|
|
|
|
@given("I have a state with fix_validated as {value}")
|
|
def step_have_state_fix_validated_value(context, value):
|
|
"""Create state with specific fix_validated value."""
|
|
validated = value.lower() == "true"
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": validated,
|
|
"current_fix": {"description": "Fix", "code": "code"},
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@then("the result success should match fix_validated")
|
|
def step_result_success_matches_validated(context):
|
|
"""Verify result success matches fix_validated."""
|
|
result = context.state.get("result", {})
|
|
fix_validated = context.state.get("fix_validated", False)
|
|
assert result.get("success") == fix_validated
|
|
|
|
|
|
@given("I have a state with detailed current fix")
|
|
def step_have_state_detailed_fix(context):
|
|
"""Create state with detailed current fix."""
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": True,
|
|
"current_fix": {"description": "Detailed fix", "code": "detailed code"},
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@then("the result fix should contain description")
|
|
def step_result_fix_has_description(context):
|
|
"""Verify result fix has description."""
|
|
result = context.state.get("result", {})
|
|
fix = result.get("fix", {})
|
|
assert "description" in fix
|
|
|
|
|
|
@then("the result fix should contain code")
|
|
def step_result_fix_has_code(context):
|
|
"""Verify result fix has code."""
|
|
result = context.state.get("result", {})
|
|
fix = result.get("fix", {})
|
|
assert "code" in fix
|
|
|
|
|
|
@given("I have a state after first fix attempt")
|
|
def step_have_state_after_first_attempt(context):
|
|
"""Create state after first fix attempt."""
|
|
context.state = {
|
|
"messages": [{"type": "error_analysis"}],
|
|
"error_message": "Test error",
|
|
"code_context": "test code",
|
|
"attempted_fixes": [{"attempt": 1}],
|
|
"current_fix": {"description": "First fix", "code": "first code"},
|
|
}
|
|
|
|
|
|
@when("I inspect the workflow graph for auto debug")
|
|
def step_inspect_workflow_graph(context):
|
|
"""Inspect the workflow graph."""
|
|
with patch("langgraph.graph.StateGraph"):
|
|
context.graph = context.agent._build_graph()
|
|
|
|
|
|
@given("I have a state with any current fix")
|
|
def step_have_state_any_current_fix(context):
|
|
"""Create state with any current fix."""
|
|
context.state = {
|
|
"messages": [],
|
|
"current_fix": {"description": "Any fix", "code": "any code"},
|
|
"attempted_fixes": [],
|
|
}
|
|
|
|
|
|
@then("the fix_validated field should be present")
|
|
def step_fix_validated_field_present(context):
|
|
"""Verify fix_validated field is present."""
|
|
assert "fix_validated" in context.state
|
|
|
|
|
|
@given("I have a state with fix_validated {value} and {count:d} attempt")
|
|
def step_have_state_validated_and_attempt(context, value, count):
|
|
"""Create state with fix_validated value and attempt count."""
|
|
validated = value.lower() == "true"
|
|
context.state = {
|
|
"messages": [],
|
|
"fix_validated": validated,
|
|
"attempted_fixes": [{"attempt": i} for i in range(count)],
|
|
}
|
|
|
|
|
|
@when("I create an AutoDebugAgent with max_fix_attempts of {value:d}")
|
|
def step_create_agent_with_max_attempts(context, value):
|
|
"""Create agent with specific max_fix_attempts."""
|
|
with patch(
|
|
"cleveragents.application.agents.base_agent.BaseAgent._create_llm"
|
|
) as mock_create_llm:
|
|
mock_create_llm.return_value = context.mock_llm
|
|
context.agent = context.AutoDebugAgent(max_fix_attempts=value)
|
|
|
|
|
|
@when("I create an AutoDebugAgent with provider_kwargs:")
|
|
def step_create_agent_with_provider_kwargs(context):
|
|
"""Create agent with provider_kwargs."""
|
|
kwargs = {}
|
|
for row in context.table:
|
|
kwarg = row["kwarg"]
|
|
value = row["value"]
|
|
# Convert to appropriate type
|
|
try:
|
|
kwargs[kwarg] = int(value)
|
|
except ValueError:
|
|
try:
|
|
kwargs[kwarg] = float(value)
|
|
except ValueError:
|
|
kwargs[kwarg] = value
|
|
|
|
with patch(
|
|
"cleveragents.application.agents.base_agent.BaseAgent._create_llm"
|
|
) as mock_create_llm:
|
|
mock_create_llm.return_value = context.mock_llm
|
|
context.agent = context.AutoDebugAgent(**kwargs)
|
|
|
|
|
|
@then("the agent should have provider_kwargs stored")
|
|
def step_agent_has_provider_kwargs(context):
|
|
"""Verify agent has provider_kwargs stored."""
|
|
assert hasattr(context.agent, "provider_kwargs")
|