BeatDebate / Design /agents_refactoring_design.md
SulmanK's picture
Comprehensive refactoring of the codebase to eliminate significant duplication and enhance modularity - Updated the design document to reflect a unified architecture across agents, API clients, and services. Introduced shared components for HTTP handling, rate limiting, and metadata models, leading to improved maintainability and reduced file sizes. Established a clear separation of concerns and streamlined agent logic for better performance and easier testing.
3156c41
|
Raw
History Blame Contribute Delete
16.7 kB
# Comprehensive Codebase Refactoring Design Document
## Problem Statement
**Current State:**
- Large, monolithic agent files (1000+ lines) that are difficult to maintain and test
- Mixed responsibilities within single agent classes (query understanding, execution, evaluation)
- Tightly coupled components making individual testing challenging
- **SIGNIFICANT CODE DUPLICATION ACROSS ENTIRE CODEBASE:**
- **Agents**: Two separate candidate generators, duplicate entity extraction, JSON parsing, LLM calls
- **API Clients**: Duplicate `_make_request` implementations in LastFM and Spotify clients
- **Rate Limiting**: Duplicate rate limiting logic across multiple clients
- **Error Handling**: Similar error handling patterns across API clients
- **Client Instantiation**: Repeated client creation patterns across agents
- **Metadata Models**: Similar track/artist metadata structures across clients
**Desired State:**
- Modular architecture with focused, smaller files (<500 lines each)
- **UNIFIED SHARED COMPONENTS** eliminating duplication across entire codebase
- **CONSOLIDATED API LAYER** with shared HTTP client and rate limiting
- **UNIFIED METADATA MODELS** across all services
- **SHARED UTILITIES** for common operations (logging, caching, error handling)
- Clear separation of concerns between all layers
**Value Proposition:**
- **Eliminate ~40% code duplication** through comprehensive consolidation
- Single source of truth for HTTP requests, rate limiting, and error handling
- Unified metadata models across all services
- Faster development cycles through improved code organization
- Easier testing of shared utilities and API components
- Reduced maintenance burden from duplicate logic across entire codebase
## Comprehensive Architecture Design
### Overall Philosophy
- **Layered Architecture**: Clear separation between agents, services, API clients, and utilities
- **Shared Components**: All common functionality consolidated into reusable components
- **Unified Interfaces**: Consistent interfaces across all API clients and services
- **Single Responsibility**: Each component has a focused, well-defined purpose
### **EXPANDED: Target Directory Structure**
```
src/
├── api/ # API Layer - Unified HTTP & External Services
│ ├── __init__.py
│ ├── base_client.py # NEW: Base HTTP client with shared request logic
│ ├── rate_limiter.py # NEW: Unified rate limiting for all APIs
│ ├── lastfm_client.py # REFACTORED: Uses base_client
│ ├── spotify_client.py # REFACTORED: Uses base_client
│ └── client_factory.py # NEW: Factory for creating configured clients
├── models/ # Data Models & Schemas
│ ├── __init__.py
│ ├── metadata_models.py # NEW: Unified track/artist metadata models
│ ├── api_models.py # NEW: API request/response models
│ ├── agent_models.py # EXISTING: Agent workflow models
│ └── recommendation_models.py # EXISTING: Recommendation result models
├── services/ # Business Logic Services
│ ├── __init__.py
│ ├── recommendation_engine.py # REFACTORED: Uses unified components
│ ├── smart_context_manager.py # EXISTING: Context management service
│ ├── cache_manager.py # EXISTING: Caching service
│ └── metadata_service.py # NEW: Unified metadata operations
├── agents/ # Agent Layer - Simplified with Shared Components
│ ├── __init__.py
│ ├── base_agent.py # EXISTING: Base agent class
│ ├── components/ # Shared Agent Components
│ │ ├── __init__.py
│ │ ├── unified_candidate_generator.py # UNIFIED: Replaces both generators
│ │ ├── quality_scorer.py # MOVED: From root agents/
│ │ ├── entity_extraction_utils.py # NEW: Consolidated extraction methods
│ │ ├── llm_utils.py # NEW: Shared LLM calling & JSON parsing
│ │ └── query_analysis_utils.py # NEW: Shared query analysis patterns
│ ├── planner/
│ │ ├── __init__.py
│ │ ├── agent.py # SIMPLIFIED: PlannerAgent class
│ │ ├── query_understanding_engine.py # MOVED: QueryUnderstandingEngine
│ │ └── entity_recognizer.py # CONDITIONAL: Enhanced entity recognizer
│ ├── genre_mood/
│ │ ├── __init__.py
│ │ ├── agent.py # SIMPLIFIED: GenreMoodAgent class
│ │ ├── mood_logic.py # OPTIONAL: Mood mapping helpers
│ │ └── tag_generator.py # OPTIONAL: Search tag generation
│ ├── discovery/
│ │ ├── __init__.py
│ │ ├── agent.py # SIMPLIFIED: DiscoveryAgent class
│ │ ├── similarity_explorer.py # MOVED: MultiHopSimilarityExplorer
│ │ └── underground_detector.py # MOVED: UndergroundDetector
│ └── judge/
│ ├── __init__.py
│ ├── agent.py # SIMPLIFIED: JudgeAgent class
│ ├── ranking_logic.py # MOVED: Scoring components
│ └── explainer.py # MOVED: ConversationalExplainer
└── utils/ # Shared Utilities
├── __init__.py
├── logging_config.py # EXISTING: Logging configuration
├── http_utils.py # NEW: HTTP utilities and error handling
├── retry_utils.py # NEW: Retry logic and exponential backoff
└── validation_utils.py # NEW: Data validation and parsing utilities
```
## **NEW: API Layer Consolidation**
### **1. Base HTTP Client (`src/api/base_client.py`)**
**Consolidates**: Duplicate `_make_request` implementations
```python
class BaseAPIClient:
"""Base HTTP client with unified request handling, rate limiting, and error handling."""
def __init__(
self,
base_url: str,
rate_limiter: "RateLimiter",
timeout: int = 10
):
self.base_url = base_url
self.rate_limiter = rate_limiter
self.timeout = timeout
self.session: Optional[aiohttp.ClientSession] = None
async def _make_request(
self,
endpoint: str,
params: Optional[Dict[str, Any]] = None,
method: str = "GET",
retries: int = 3
) -> Dict[str, Any]:
"""Unified request method with rate limiting, retries, and error handling."""
async def _handle_api_error(self, response: aiohttp.ClientResponse, endpoint: str):
"""Unified API error handling across all clients."""
async def _exponential_backoff(self, attempt: int, base_delay: float = 1.0):
"""Unified exponential backoff strategy."""
```
### **2. Unified Rate Limiter (`src/api/rate_limiter.py`)**
**Consolidates**: All rate limiting logic across clients
```python
class UnifiedRateLimiter:
"""Unified rate limiter supporting multiple rate limit strategies."""
def __init__(self, calls_per_second: float = None, calls_per_hour: int = None):
self.calls_per_second = calls_per_second
self.calls_per_hour = calls_per_hour
# Unified rate limiting implementation
async def wait_if_needed(self):
"""Unified rate limiting logic for all API clients."""
```
### **3. Refactored API Clients**
Both `LastFmClient` and `SpotifyClient` will:
- Inherit from `BaseAPIClient`
- Remove duplicate `_make_request` implementations
- Use unified rate limiting
- Use shared error handling
- Focus only on API-specific logic
### **4. Client Factory (`src/api/client_factory.py`)**
**Consolidates**: Repeated client instantiation patterns
```python
class APIClientFactory:
"""Factory for creating configured API clients."""
@staticmethod
async def create_lastfm_client(api_key: str, rate_limit: float = 3.0) -> LastFmClient:
"""Create configured Last.fm client."""
@staticmethod
async def create_spotify_client(
client_id: str,
client_secret: str,
rate_limit: int = 50
) -> SpotifyClient:
"""Create configured Spotify client."""
```
## **NEW: Models Layer Consolidation**
### **1. Unified Metadata Models (`src/models/metadata_models.py`)**
**Consolidates**: Similar track/artist metadata across clients
```python
@dataclass
class UnifiedTrackMetadata:
"""Unified track metadata across all services."""
name: str
artist: str
album: Optional[str] = None
# Common fields across LastFM and Spotify
# Service-specific data in 'source_data' field
@dataclass
class UnifiedArtistMetadata:
"""Unified artist metadata across all services."""
name: str
# Common fields with service-specific extensions
```
### **2. API Models (`src/models/api_models.py`)**
**NEW**: Request/response models for API operations
```python
class SearchRequest(BaseModel):
"""Unified search request model."""
class MetadataRequest(BaseModel):
"""Unified metadata request model."""
```
## **NEW: Services Layer Enhancement**
### **1. Metadata Service (`src/services/metadata_service.py`)**
**NEW**: Unified metadata operations across all clients
```python
class MetadataService:
"""Unified service for metadata operations across all APIs."""
def __init__(self, lastfm_client: LastFmClient, spotify_client: SpotifyClient):
self.lastfm_client = lastfm_client
self.spotify_client = spotify_client
async def get_unified_track_metadata(
self,
artist: str,
track: str
) -> UnifiedTrackMetadata:
"""Get unified track metadata from multiple sources."""
async def search_tracks_unified(self, query: str) -> List[UnifiedTrackMetadata]:
"""Search tracks across multiple services with unified results."""
```
## **NEW: Utils Layer Expansion**
### **1. HTTP Utils (`src/utils/http_utils.py`)**
**NEW**: Shared HTTP utilities
```python
class HTTPUtils:
@staticmethod
def build_query_params(params: Dict[str, Any]) -> str:
"""Build query parameters with proper encoding."""
@staticmethod
def parse_api_error(response: aiohttp.ClientResponse) -> Dict[str, Any]:
"""Parse API error responses with consistent format."""
```
### **2. Retry Utils (`src/utils/retry_utils.py`)**
**NEW**: Shared retry logic
```python
class RetryUtils:
@staticmethod
async def exponential_backoff(
attempt: int,
base_delay: float = 1.0,
max_delay: float = 60.0
):
"""Exponential backoff with jitter."""
@staticmethod
def should_retry(exception: Exception, attempt: int, max_attempts: int) -> bool:
"""Determine if operation should be retried."""
```
## **EXPANDED: Agent Layer Consolidation**
### **Updated: Agent Simplification Strategy**
#### **Remove Client Instantiation from Agents**
All agents currently create their own `LastFmClient` instances:
```python
# REMOVE THIS PATTERN from all agents:
from ..api.lastfm_client import LastFmClient
async with LastFmClient(api_key=self.lastfm.api_key) as client:
```
**Replace with**:
```python
# Agents receive configured clients via dependency injection
# Use MetadataService for unified operations
```
#### **Eliminate Rate Limit Duplication**
All agents currently store: `self.lastfm_rate_limit = lastfm_client.rate_limiter.calls_per_second`
**Replace with**: Shared configuration through `MetadataService`
## **EXPANDED: Duplication Elimination Strategy**
### **Phase 1: Core Infrastructure**
1. **Create base HTTP client** with unified request handling
2. **Create unified rate limiter** for all APIs
3. **Create unified metadata models** replacing service-specific ones
4. **Create client factory** for standardized client creation
### **Phase 2: API Layer Refactoring**
1. **Refactor LastFM client** to use base client
2. **Refactor Spotify client** to use base client
3. **Remove duplicate HTTP and error handling code**
4. **Implement unified rate limiting**
### **Phase 3: Services Layer Enhancement**
1. **Create metadata service** for unified operations
2. **Update recommendation engine** to use unified services
3. **Integrate with existing cache manager** and context manager
### **Phase 4: Agent Layer Simplification**
1. **Remove client instantiation** from agents
2. **Replace with dependency injection** of configured services
3. **Implement unified candidate generator**
4. **Consolidate utility methods** into shared components
### **Phase 5: Utils Layer Completion**
1. **Extract HTTP utilities** from API clients
2. **Extract retry logic** into shared utilities
3. **Create validation utilities** for consistent data handling
## **EXPANDED: File Size Reduction Targets**
| Component | Current Size | Target Size | Reduction |
|-----------|-------------|-------------|-----------|
| **Agents Layer** |
| PlannerAgent | 1276 lines | <400 lines | 68% |
| JudgeAgent | 1361 lines | <300 lines | 78% |
| DiscoveryAgent | 1316 lines | <400 lines | 70% |
| GenreMoodAgent | 985 lines | <300 lines | 70% |
| **API Layer** |
| LastFmClient | 630 lines | <400 lines | 37% |
| SpotifyClient | 511 lines | <350 lines | 32% |
| **Services Layer** |
| RecommendationEngine | 809 lines | <500 lines | 38% |
**Total Reduction**: ~60% in main files + elimination of duplicate utility code across entire codebase
## **EXPANDED: Implementation Plan**
### **Step 1: Core Infrastructure (API Layer Foundation)**
```bash
mkdir -p src/api src/models src/utils
```
- Create `src/api/base_client.py` with unified HTTP handling
- Create `src/api/rate_limiter.py` with unified rate limiting
- Create `src/models/metadata_models.py` with unified data models
- Create `src/utils/http_utils.py` and `src/utils/retry_utils.py`
### **Step 2: API Layer Consolidation**
1. **Extract common patterns** from existing API clients
2. **Refactor LastFM and Spotify clients** to use base infrastructure
3. **Create client factory** for standardized instantiation
4. **Test API compatibility** with existing functionality
### **Step 3: Services Layer Enhancement**
1. **Create metadata service** with unified operations
2. **Update recommendation engine** to use new services
3. **Integrate with cache manager** for performance
4. **Test service layer compatibility**
### **Step 4: Agent Layer Refactoring (As Previously Planned)**
1. **Create shared agent components**
2. **Simplify agent classes** removing duplicate utilities
3. **Move agents to subdirectories** with focused responsibilities
4. **Update all imports** and dependencies
### **Step 5: Integration & Validation**
1. **Update all import statements** across codebase
2. **Run comprehensive test suite** for all layers
3. **Performance validation** ensuring no degradation
4. **Integration testing** of complete workflow
## **EXPANDED: Success Criteria**
1. **API Layer**: No duplicate HTTP handling or rate limiting logic
2. **Models Layer**: Unified metadata models across all services
3. **Services Layer**: Consolidated business logic with clear interfaces
4. **Agents Layer**: No duplicate utility methods, <500 lines per file
5. **Utils Layer**: Shared utilities for all common operations
6. **Functionality Preservation**: All existing capabilities maintained
7. **Performance Maintenance**: No significant performance degradation
8. **Test Compatibility**: All existing tests pass with minimal changes
## **EXPANDED: Expected Impact**
- **Code Reduction**: ~5000 lines of duplicate code eliminated across entire codebase
- **Maintenance**: Single source of truth for HTTP, rate limiting, metadata, and common operations
- **Testing**: All shared components can be tested in isolation
- **Development**: Consistent patterns across all layers, easier to add new features
- **Architecture**: Clean separation of concerns with comprehensive shared utilities
- **Performance**: Optimized HTTP handling and caching through unified components
This comprehensive refactoring will transform the entire codebase from having significant duplication across all layers into a clean, modular architecture with substantial reduction in complexity and maintenance burden throughout the system.