Source code for atloop.orchestrator.phases.discover

"""DISCOVER phase implementation."""

import logging

from atloop.memory.summarizer import MemorySummarizer
from atloop.orchestrator.phases.base import BasePhase, PhaseContext, PhaseResult
from atloop.orchestrator.state_machine import Phase

logger = logging.getLogger(__name__)


[docs] class DiscoverPhase(BasePhase): """DISCOVER phase: Build context and prepare for planning."""
[docs] def execute(self, context: PhaseContext) -> PhaseResult: """ Execute DISCOVER phase. Args: context: Phase execution context Returns: Phase execution result """ logger.debug(f"[DiscoverPhase] Executing DISCOVER phase at step {context.step}") state = self.coordinator.state_manager.agent_state try: # Check if context_builder is initialized if self.coordinator.context_builder is None: logger.error("[DiscoverPhase] ContextBuilder not initialized") return PhaseResult( success=False, data={}, next_phase=Phase.FAIL, error="ContextBuilder not initialized", ) # Build memory summary logger.debug("[DiscoverPhase] Building memory summary") memory_config = getattr(self.coordinator.config, "memory", None) if memory_config: memory_summary_max_length = memory_config.summary_max_length logger.debug( f"[DiscoverPhase] Using memory config: max_length={memory_summary_max_length}" ) else: memory_summary_max_length = 64000 logger.debug( f"[DiscoverPhase] Using default memory summary max length: {memory_summary_max_length}" ) memory_summary = MemorySummarizer.summarize( state, max_length=memory_summary_max_length, task_goal=self.coordinator.task_spec.goal, ) logger.debug( f"[DiscoverPhase] Memory summary length: {len(memory_summary)} chars (max: {memory_summary_max_length})" ) # Extract keywords logger.debug("[DiscoverPhase] Extracting keywords") keywords = self._extract_keywords() logger.debug(f"[DiscoverPhase] Extracted {len(keywords)} keywords: {keywords[:5]}") # Build context pack logger.debug("[DiscoverPhase] Building context pack") context_pack = self.coordinator.context_builder.build( goal=self.coordinator.task_spec.goal, constraints=self.coordinator.task_spec.constraints, recent_error=state.last_error.summary, current_diff=state.artifacts.current_diff, test_results=state.artifacts.test_results, verification_success=state.artifacts.verification_success, memory_summary=memory_summary, keywords=keywords, ) logger.debug( f"[DiscoverPhase] Context pack built: project_profile={context_pack.project_profile}" ) # Store context pack for PLAN phase self.coordinator.job_state.shared_data["context_pack"] = context_pack.to_string() logger.debug("[DiscoverPhase] Context pack stored in job_state") # Transition to PLAN logger.debug("[DiscoverPhase] Transitioning to PLAN phase") transition_result = self._transition(Phase.PLAN) if not transition_result: logger.error("[DiscoverPhase] Transition failed: DISCOVER -> PLAN") return PhaseResult( success=False, data={}, next_phase=Phase.FAIL, error="State transition failed: DISCOVER -> PLAN", ) self.coordinator.state_manager.update(phase="PLAN") logger.info("[DiscoverPhase] Successfully transitioned to PLAN phase") return PhaseResult( success=True, data={"context_pack": context_pack.to_string()}, next_phase=Phase.PLAN, ) except Exception as e: logger.error(f"[DiscoverPhase] Error: {e}") logger.debug( f"[DiscoverPhase] Exception details: {type(e).__name__}: {e}", exc_info=True ) return PhaseResult( success=False, data={}, next_phase=Phase.FAIL, error=str(e), )
def _extract_keywords(self) -> list[str]: """Extract keywords from state.""" keywords = [] state = self.coordinator.state_manager.agent_state # Extract from goal if self.coordinator.task_spec.goal: keywords.extend( self.coordinator.indexer.extract_keywords(self.coordinator.task_spec.goal) ) # Extract from error if state.last_error.summary: keywords.extend(self.coordinator.indexer.extract_keywords(state.last_error.summary)) return keywords[:10] # Limit to 10 keywords