diff --git a/app/config.py b/app/config.py index 1f4dfe57..213e0f88 100644 --- a/app/config.py +++ b/app/config.py @@ -268,33 +268,34 @@ def initialize_settings(): tool_settings = ToolSettings() # Validate required Meta settings - assert ( - settings.meta_api_version and settings.meta_api_version.strip() - ), "META_API_VERSION is required" - assert ( - settings.meta_app_id and settings.meta_app_id.strip() - ), "META_APP_ID is required" - assert ( + if not (settings.meta_api_version and settings.meta_api_version.strip()): + raise ValueError("META_API_VERSION is required") + if not (settings.meta_app_id and settings.meta_app_id.strip()): + raise ValueError("META_APP_ID is required") + if not ( settings.meta_app_secret and settings.meta_app_secret.get_secret_value().strip() - ), "META_APP_SECRET is required" + ): + raise ValueError("META_APP_SECRET is required") # Validate required WhatsApp settings - assert ( + if not ( settings.whatsapp_cloud_number_id and settings.whatsapp_cloud_number_id.strip() - ), "WHATSAPP_CLOUD_NUMBER_ID is required" - assert ( + ): + raise ValueError("WHATSAPP_CLOUD_NUMBER_ID is required") + if not ( settings.whatsapp_verify_token and settings.whatsapp_verify_token.get_secret_value().strip() - ), "WHATSAPP_VERIFY_TOKEN is required" - assert ( + ): + raise ValueError("WHATSAPP_VERIFY_TOKEN is required") + if not ( settings.whatsapp_api_token and settings.whatsapp_api_token.get_secret_value().strip() - ), "WHATSAPP_API_TOKEN is required" + ): + raise ValueError("WHATSAPP_API_TOKEN is required") # Validate other required settings - assert ( - settings.database_url and settings.database_url.get_secret_value().strip() - ), "DATABASE_URL is required" + if not (settings.database_url and settings.database_url.get_secret_value().strip()): + raise ValueError("DATABASE_URL is required") return settings, llm_settings, embedding_settings, tool_settings diff --git a/app/services/messaging_service.py b/app/services/messaging_service.py index f88e1649..0ec3a9a4 100644 --- a/app/services/messaging_service.py +++ b/app/services/messaging_service.py @@ -62,7 +62,8 @@ async def handle_command_message( self, user: models.User, message: models.Message ) -> JSONResponse: self.logger.debug(f"Handling command message: {message.content}") - assert message.content is not None + if message.content is None: + raise ValueError("Command message content is unexpectedly None.") key = message.content.lower() handler = self._command_handlers.get(key, self._command_unknown) await handler(user) diff --git a/app/services/onboarding_service.py b/app/services/onboarding_service.py index aef34d6a..9d853d40 100644 --- a/app/services/onboarding_service.py +++ b/app/services/onboarding_service.py @@ -22,7 +22,8 @@ async def process_state(self, user: User): self.logger.debug( f"Onboarding user {user.wa_id} with onboarding_state {user.onboarding_state}" ) - assert user.onboarding_state is not None + if user.onboarding_state is None: + raise ValueError("User onboarding_state is unexpectedly None.") onboarding_handler = self.handlers.get( user.onboarding_state, self.handle_default ) diff --git a/app/services/rate_limit_service.py b/app/services/rate_limit_service.py index 5a0cd006..075d295b 100644 --- a/app/services/rate_limit_service.py +++ b/app/services/rate_limit_service.py @@ -99,7 +99,8 @@ async def check_rate_limit_and_update_state( # Check user limit user_key = RedisKeys.USER_RATE(phone_number) - assert settings.user_message_limit is not None + if settings.user_message_limit is None: + raise ValueError("User message rate limit is unexpectedly None.") is_exceeded, result = await self._check_rate_limit( key=user_key, limit=settings.user_message_limit, @@ -122,7 +123,8 @@ async def check_rate_limit_and_update_state( # Check global limit global_key = RedisKeys.GLOBAL_RATE - assert settings.global_message_limit is not None + if settings.global_message_limit is None: + raise ValueError("Global message rate limit is unexpectedly None.") is_exceeded, result = await self._check_rate_limit( key=global_key, limit=settings.global_message_limit, @@ -167,7 +169,8 @@ async def _check_rate_limit( if redis is None: return False, 0 - assert settings.time_to_live + if not settings.time_to_live: + raise ValueError("Rate limit TTL is missing or zero.") pipe = await redis.pipeline() await pipe.incr(key) await pipe.expire(key, settings.time_to_live) diff --git a/app/services/state_service.py b/app/services/state_service.py index 9627e001..81d9c605 100644 --- a/app/services/state_service.py +++ b/app/services/state_service.py @@ -23,7 +23,8 @@ def __init__(self): self.logger = logging.getLogger(__name__) async def handle_blocked(self, user: User) -> JSONResponse: - assert user.id is not None + if user.id is None: + raise ValueError("User ID is unexpectedly None for blocked state handling.") blocked_text = strings.get_string(StringCategory.ERROR, "blocked") last_assistant_message = await db.get_latest_user_message_by_role( @@ -57,7 +58,10 @@ async def handle_blocked(self, user: User) -> JSONResponse: ) async def handle_rate_limited(self, user: User) -> JSONResponse: - assert user.id is not None + if user.id is None: + raise ValueError( + "User ID is unexpectedly None for rate-limited state handling." + ) rate_limit_text = strings.get_string(StringCategory.ERROR, "rate_limited") last_assistant_message = await db.get_latest_user_message_by_role( @@ -184,7 +188,8 @@ async def handle_new_user_registration( ) await whatsapp_client.send_message(phone_number, response_text) - assert new_user.id is not None + if new_user.id is None: + raise ValueError("New user ID is unexpectedly None after registration.") await db.create_new_message_by_fields( user_id=new_user.id, role=MessageRole.assistant, @@ -208,7 +213,8 @@ async def handle_new_user_registration( async def handle_in_review_user(self, user: User) -> JSONResponse: """Handle messages from users in review (not yet approved) users""" - assert user.id is not None + if user.id is None: + raise ValueError("User ID is unexpectedly None for in-review handling.") pending_text = strings.get_string( StringCategory.REGISTRATION, "pending_approval" @@ -254,7 +260,10 @@ async def handle_new_approved_user(self, user: User) -> JSONResponse: language_code="en_US", ) - assert user.id is not None + if user.id is None: + raise ValueError( + "User ID is unexpectedly None after approval template send." + ) await db.create_new_message_by_fields( user_id=user.id, role=MessageRole.assistant, @@ -266,7 +275,10 @@ async def handle_new_approved_user(self, user: User) -> JSONResponse: await flow_client.send_personal_and_school_info_flow(user) else: # In non-production, skip template and flow - assert user.id is not None + if user.id is None: + raise ValueError( + "User ID is unexpectedly None in non-production approval flow." + ) self.logger.info( f"Skipping template and flow for user {user.wa_id} in {settings.environment} environment" ) @@ -314,11 +326,13 @@ async def handle_new_dummy(self, user: User) -> JSONResponse: # Read the class IDs from the class info class_ids = await db.get_class_ids_from_class_info(user.class_info) - assert class_ids is not None + if class_ids is None: + raise ValueError("Derived class IDs are unexpectedly None.") # Update user and create teachers_classes entries user = await db.update_user(user) - assert user.id is not None + if user.id is None: + raise ValueError("Dummy user ID is unexpectedly None after update.") await db.assign_teacher_to_classes(user, class_ids) # Send a welcome message to the user diff --git a/app/tools/tool_code/generate_exercise/main.py b/app/tools/tool_code/generate_exercise/main.py index e94d40aa..dd572609 100644 --- a/app/tools/tool_code/generate_exercise/main.py +++ b/app/tools/tool_code/generate_exercise/main.py @@ -19,7 +19,8 @@ async def generate_exercise( try: # Retrieve the resources for the class resource_ids = await db.get_class_resources(class_id) - assert resource_ids + if not resource_ids: + raise ValueError(f"No resources found for class {class_id}.") # Retrieve the relevant content and exercises retrieved_content = await vector_search( @@ -86,7 +87,8 @@ async def generate_exercise( ), }, ) - assert response.content + if not response.content: + raise ValueError("LLM returned empty exercise content.") # Convert content to string if it's not already content = response.content diff --git a/app/tools/tool_code/search_knowledge/main.py b/app/tools/tool_code/search_knowledge/main.py index 0d5fff8b..b9ab08ca 100644 --- a/app/tools/tool_code/search_knowledge/main.py +++ b/app/tools/tool_code/search_knowledge/main.py @@ -15,7 +15,8 @@ async def search_knowledge( try: # Retrieve the resources for the class resource_ids = await db.get_class_resources(class_id) - assert resource_ids + if not resource_ids: + raise ValueError(f"No resources found for class {class_id}.") # Retrieve the relevant content retrieved_content = await vector_search(