Source code for atloop.orchestrator.phases.verify
"""VERIFY phase implementation."""
import logging
from atloop.config.limits import ERROR_SUMMARY_LIMIT_NORMAL, TEST_RESULTS_LIMIT
from atloop.orchestrator.phases.base import BasePhase, PhaseContext, PhaseResult
from atloop.orchestrator.state_machine import Phase
logger = logging.getLogger(__name__)
[docs]
class VerifyPhase(BasePhase):
"""VERIFY phase: Run verification tests."""
[docs]
def execute(self, context: PhaseContext) -> PhaseResult:
"""
Execute VERIFY phase.
Args:
context: Phase execution context
Returns:
Phase execution result
"""
logger.debug(f"[VerifyPhase] Executing VERIFY phase at step {context.step}")
state = self.coordinator.state_manager.agent_state
try:
# Run verification
logger.debug("[VerifyPhase] Running verification")
verification_result = self.coordinator.verifier.verify()
logger.debug(
f"[VerifyPhase] Verification result: success={verification_result.success}, command={verification_result.command}"
)
# Log verification result
self.coordinator.event_logger.log_verification(
step=state.step,
success=verification_result.success,
command=verification_result.command,
stdout=verification_result.stdout,
stderr=verification_result.stderr,
)
# Update artifacts with test results
test_output = ""
if verification_result.stdout:
test_output += verification_result.stdout
if verification_result.stderr:
if test_output:
test_output += "\n\n=== STDERR ===\n"
test_output += verification_result.stderr
if test_output:
state.artifacts.test_results = test_output[:TEST_RESULTS_LIMIT]
logger.debug(
f"[VerifyPhase] Test results stored: {len(test_output)} chars (limited to {TEST_RESULTS_LIMIT})"
)
# Update last error if verification failed
if not verification_result.success and verification_result.command:
logger.debug("[VerifyPhase] Verification failed, updating error state")
error_msg_parts = []
if verification_result.error_summary:
error_msg_parts.append(
f"Verification error summary:\n{verification_result.error_summary}"
)
test_output = ""
if verification_result.stdout:
test_output += verification_result.stdout
if verification_result.stderr:
if test_output:
test_output += "\n\n=== STDERR ===\n"
test_output += verification_result.stderr
if test_output:
error_msg_parts.append(
f"\nFull test output:\n{test_output[:TEST_RESULTS_LIMIT]}"
)
error_summary_text = (
"\n".join(error_msg_parts) if error_msg_parts else "Verification failed"
)
state.last_error.summary = error_summary_text[:ERROR_SUMMARY_LIMIT_NORMAL]
state.last_error.repro_cmd = verification_result.command
logger.debug(
f"[VerifyPhase] Error state updated: summary length={len(state.last_error.summary)}"
)
# Store verification result
state.artifacts.verification_success = verification_result.success
logger.debug(
f"[VerifyPhase] Verification success stored: {verification_result.success}"
)
# Task completion detection: Check if task goal is achieved
task_goal = self.coordinator.task_spec.goal.lower()
if state.memory.created_files and task_goal:
# Simple heuristic: if goal contains "write" and "code" and file exists, task might be complete
if ("write" in task_goal or "create" in task_goal) and (
"code" in task_goal or "file" in task_goal or "python" in task_goal
):
logger.info(
f"[VerifyPhase] Task completion detected: "
f"goal='{self.coordinator.task_spec.goal}', "
f"created_files={state.memory.created_files}"
)
# Add completion hint to state for next PLAN phase
state.memory.notes.append(
f"Task completion hint: File(s) {state.memory.created_files} created. "
f"Task goal '{self.coordinator.task_spec.goal}' appears to be achieved. "
f"Consider setting stop_reason='done' if task is complete."
)
logger.info("[VerifyPhase] Added task completion hint to memory.notes")
# Transition to DISCOVER (let LLM decide in PLAN phase)
logger.debug("[VerifyPhase] Transitioning to DISCOVER phase")
self._transition(Phase.DISCOVER)
self.coordinator.state_manager.update(phase="DISCOVER")
logger.info("[VerifyPhase] Successfully transitioned to DISCOVER phase")
return PhaseResult(
success=True,
data={"verification_result": verification_result},
next_phase=Phase.DISCOVER,
)
except Exception as e:
logger.error(f"[VerifyPhase] Error: {e}")
logger.debug(f"[VerifyPhase] Exception details: {type(e).__name__}: {e}", exc_info=True)
state = self.coordinator.state_manager.agent_state
state.last_error.summary = f"VERIFY phase error: {e}"
self.coordinator.state_manager.update(phase="FAIL")
self._transition(Phase.FAIL)
return PhaseResult(
success=False,
data={},
next_phase=Phase.FAIL,
error=str(e),
)