""" Base simulator class for all service integrations. All service-specific simulators inherit from this class. """ from abc import ABC, abstractmethod from typing import Any, Dict, Optional import json class BaseSimulator(ABC): """Base class for all service simulators.""" def __init__(self, service_name: str): self.service_name = service_name self.mock_responses = {} self.load_mock_responses() @abstractmethod def load_mock_responses(self): """Load mock responses for this service.""" pass @abstractmethod def get_required_permissions(self, action: str) -> set[str]: """Get required permissions for an action.""" pass @abstractmethod def validate_params(self, action: str, params: dict) -> tuple[bool, Optional[str]]: """ Validate parameters for an action. Returns: (is_valid, error_message) """ pass @abstractmethod def generate_mock_response(self, action: str, params: dict) -> dict: """Generate a realistic mock response for the action.""" pass def execute(self, action: str, params: dict, mock: bool = True, credentials: Optional[dict] = None) -> dict: """ Execute an API action (mock or real). Args: action: The action to perform (e.g., 'get_pull_request') params: Parameters for the action mock: If True, return mock response. If False, call real API. credentials: API credentials (required for real mode) Returns: Response dict with data or error """ # Validate parameters is_valid, error_msg = self.validate_params(action, params) if not is_valid: return { 'success': False, 'error': 'INVALID_PARAMS', 'message': error_msg, 'service': self.service_name, 'action': action } if mock: return self._execute_mock(action, params) else: if not credentials: return { 'success': False, 'error': 'MISSING_CREDENTIALS', 'message': 'Credentials required for real API calls', 'service': self.service_name, 'action': action } return self._execute_real(action, params, credentials) def _execute_mock(self, action: str, params: dict) -> dict: """Execute in mock mode.""" try: response_data = self.generate_mock_response(action, params) return { 'success': True, 'mode': 'mock', 'service': self.service_name, 'action': action, 'data': response_data, 'note': '⚡ This was a simulated response - no real API call made' } except Exception as e: return { 'success': False, 'error': 'MOCK_GENERATION_ERROR', 'message': str(e), 'service': self.service_name, 'action': action } def _execute_real(self, action: str, params: dict, credentials: dict) -> dict: """ Execute real API call. Subclasses should override this to implement real API calls. """ return { 'success': False, 'error': 'NOT_IMPLEMENTED', 'message': f'Real API mode not yet implemented for {self.service_name}.{action}', 'service': self.service_name, 'action': action, 'note': 'Override _execute_real() in your simulator to enable real API calls' } def estimate_tokens(self, response: dict) -> int: """ Estimate token count for a response. Uses simple heuristic: ~4 characters per token for JSON. Will be improved with tiktoken in later phases. """ response_str = json.dumps(response) return len(response_str) // 4 def get_action_list(self) -> list[str]: """Get list of available actions for this service.""" return list(self.mock_responses.keys())