diff --git a/modules/features/chatbot/mainChatbot.py b/modules/features/chatbot/mainChatbot.py index 2ddb71c9..84947bdd 100644 --- a/modules/features/chatbot/mainChatbot.py +++ b/modules/features/chatbot/mainChatbot.py @@ -204,7 +204,7 @@ def getChatStreamingHelper(): def __get_placeholder_user(): """Placeholder user for contexts that only need service resolution (e.g. ChatStreamingHelper).""" from modules.datamodels.datamodelUam import User - return User(id="system", email="system@placeholder", firstName="System", lastName="Placeholder") + return User(id="system", username="system", email=None, fullName="System Placeholder") def getEventManager(user, mandateId: Optional[str] = None, featureInstanceId: Optional[str] = None): @@ -333,6 +333,22 @@ def getChatbotServices( hub.ai = PublicService(AiService(hub), functionsOnly=False) hub.streaming = PublicService(StreamingService(hub)) + # Resolve billing from service center (required for _preflight_billing_check and billing callback) + try: + from modules.serviceCenter import getService + from modules.serviceCenter.context import ServiceCenterContext + _workflow = workflow or type("_Placeholder", (), {"featureCode": FEATURE_CODE})() + ctx = ServiceCenterContext( + user=user, + mandate_id=mandateId, + feature_instance_id=featureInstanceId, + workflow=_workflow, + ) + hub.billing = getService("billing", ctx, legacy_hub=None) + except Exception as e: + logger.warning(f"Could not resolve billing service for chatbot: {e}") + hub.billing = None + return hub @@ -358,6 +374,7 @@ class _ChatbotServiceHub: return self._interfaceDbComponent_val chat = None ai = None + billing = None streaming = None featureCode = "chatbot" allowedProviders = None diff --git a/modules/features/chatbot/service.py b/modules/features/chatbot/service.py index 194f9afa..08ae88d0 100644 --- a/modules/features/chatbot/service.py +++ b/modules/features/chatbot/service.py @@ -19,7 +19,7 @@ from modules.datamodels.datamodelUam import User from modules.datamodels.datamodelAi import AiCallRequest, AiCallOptions, OperationTypeEnum, ProcessingModeEnum from modules.datamodels.datamodelDocref import DocumentReferenceList, DocumentItemReference from modules.shared.timeUtils import getUtcTimestamp, parseTimestamp -from modules.features.chatbot.mainChatbot import getChatbotServices +from modules.features.chatbot.mainChatbot import getChatbotServices, getChatStreamingHelper from modules.features.chatbot.chatbot import Chatbot from modules.features.chatbot.bridges.ai import AICenterChatModel, clear_workflow_allowed_providers from modules.features.chatbot.bridges.memory import DatabaseCheckpointer @@ -1391,9 +1391,9 @@ async def _processChatbotMessageLangGraph( ) # Create chatbot instance with config for dynamic tool configuration - chat_streaming_helper = None - if services.streaming: - chat_streaming_helper = services.streaming.getChatStreamingHelper() + # Use mainChatbot.getChatStreamingHelper() - resolves from service center (legacy hub.streaming has no getChatStreamingHelper) + from modules.features.chatbot.mainChatbot import getChatStreamingHelper + chat_streaming_helper = getChatStreamingHelper() if not chat_streaming_helper: logger.warning("ChatStreamingHelper not available from streaming service; message normalization may fail") chatbot = await Chatbot.create( diff --git a/modules/interfaces/interfaceRbac.py b/modules/interfaces/interfaceRbac.py index a068abe8..b16f0b24 100644 --- a/modules/interfaces/interfaceRbac.py +++ b/modules/interfaces/interfaceRbac.py @@ -199,8 +199,17 @@ def getRecordsetWithRBAC( # Add additional record filters if recordFilter: for field, value in recordFilter.items(): - whereConditions.append(f'"{field}" = %s') - whereValues.append(value) + if isinstance(value, (list, tuple)): + if len(value) == 0: + whereConditions.append("1 = 0") # Empty IN -> no matches + else: + whereConditions.append(f'"{field}" = ANY(%s)') + whereValues.append(list(value)) + elif value is None: + whereConditions.append(f'"{field}" IS NULL') + else: + whereConditions.append(f'"{field}" = %s') + whereValues.append(value) # Build the query whereClause = ""