diff --git a/kairon/async_callback/processor.py b/kairon/async_callback/processor.py index bef261b6b..2648a4500 100644 --- a/kairon/async_callback/processor.py +++ b/kairon/async_callback/processor.py @@ -82,7 +82,8 @@ async def async_callback(obj: dict, ent: dict, cb: dict, c_src: str, bot_id: str elif res := obj.get('result'): bot_response, state, invalidate = CallbackProcessor.parse_pyscript_data(res) CallbackData.update_state(ent['bot'], ent['identifier'], state, invalidate) - await ChannelMessageDispatcher.dispatch_message(bot_id, sid, bot_response, chnl) + if bot_response: + await ChannelMessageDispatcher.dispatch_message(bot_id, sid, bot_response, chnl) CallbackLog.create_success_entry(name=ent.get("action_name"), bot=bot_id, channel=chnl, @@ -151,7 +152,8 @@ async def callback_function(rsp: dict): CallbackData.update_state(entry['bot'], entry['identifier'], state, invalidate) data = bot_response logger.info(f'Pyscript output: {bot_response, state, invalidate}') - await ChannelMessageDispatcher.dispatch_message(bot, entry.get("sender_id"), data, entry.get("channel")) + if data: + await ChannelMessageDispatcher.dispatch_message(bot, entry.get("sender_id"), data, entry.get("channel")) CallbackLog.create_success_entry(name=entry.get("action_name"), bot=bot, channel=entry.get("channel"), diff --git a/kairon/shared/data/processor.py b/kairon/shared/data/processor.py index 175d2fa37..f50f4c4c2 100644 --- a/kairon/shared/data/processor.py +++ b/kairon/shared/data/processor.py @@ -4176,6 +4176,25 @@ def list_db_actions(self, bot: str, with_doc_id: bool = True): action.pop("timestamp") yield action + def list_live_agent_actions(self, bot: str, with_doc_id: bool = True): + """ + Fetches all LiveAgentActionConfig actions from collection + :param bot: bot id + :param with_doc_id: return document id along with action configuration if True + :return: List of VectorDb actions. + """ + for action in LiveAgentActionConfig.objects(bot=bot, status=True): + action = action.to_mongo().to_dict() + if with_doc_id: + action["_id"] = action["_id"].__str__() + else: + action.pop("_id") + action.pop("user") + action.pop("bot") + action.pop("status") + action.pop("timestamp") + yield action + def list_actions(self, bot: Text): all_actions = list( Actions.objects(bot=bot, status=True).aggregate( @@ -4701,7 +4720,8 @@ def save_integrated_actions(self, actions: dict, bot: Text, user: Text): ActionType.web_search_action.value: WebSearchAction, ActionType.razorpay_action.value: RazorpayAction, ActionType.pyscript_action.value: PyscriptActionConfig, - ActionType.database_action.value: DatabaseAction + ActionType.database_action.value: DatabaseAction, + ActionType.live_agent_action.value: LiveAgentActionConfig, } saved_actions = set( Actions.objects(bot=bot, status=True, type__ne=None).values_list("name") @@ -4742,6 +4762,7 @@ def load_action_configurations(self, bot: Text): action_config.update(self.load_razorpay_action(bot)) action_config.update(self.load_pyscript_action(bot)) action_config.update(self.load_database_action(bot)) + action_config.update(self.load_live_agent_action(bot)) return action_config def load_http_action(self, bot: Text): @@ -4913,6 +4934,15 @@ def load_database_action(self, bot: Text): """ return {ActionType.database_action.value: list(self.list_db_actions(bot, False))} + def load_live_agent_action(self, bot: Text): + """ + Loads live agent actions from the database + :param bot: bot id + :return: dict + """ + return {ActionType.live_agent_action.value: list(self.list_live_agent_actions(bot, False))} + + @staticmethod def get_existing_slots(bot: Text): """ diff --git a/tests/unit_test/data_processor/data_processor_test.py b/tests/unit_test/data_processor/data_processor_test.py index e93caa16d..32ee930f5 100644 --- a/tests/unit_test/data_processor/data_processor_test.py +++ b/tests/unit_test/data_processor/data_processor_test.py @@ -1136,6 +1136,26 @@ def test_edit_live_agent(self): print(live_agent) assert live_agent == {'name': 'live_agent_action', 'bot_response': 'connecting to different live agent...', 'agent_connect_response': 'Connected to live agent', 'agent_disconnect_response': 'Disconnected from live agent', 'agent_not_available_response': 'No agents available', 'dispatch_bot_response': True, 'dispatch_agent_connect_response': True, 'dispatch_agent_disconnect_response': True, 'dispatch_agent_not_available_response': True} + def test_list_live_agent_actions(self): + processor = MongoProcessor() + res = processor.load_live_agent_action(bot='test_bot') + assert res == {'live_agent_action': [ + {'name': 'live_agent_action', + 'bot_response': 'connecting to different live agent...', + 'agent_connect_response': 'Connected to live agent', + 'agent_disconnect_response': 'Disconnected from live agent', + 'agent_not_available_response': 'No agents available', + 'dispatch_bot_response': True, + 'dispatch_agent_connect_response': True, + 'dispatch_agent_disconnect_response': True, + 'dispatch_agent_not_available_response': True} + ]} + gen = processor.list_live_agent_actions('test_bot', True) + list_data = list(gen) + assert list_data[0]['name'] == 'live_agent_action' + assert list_data[0]['bot_response'] == 'connecting to different live agent...' + assert list_data[0].get('_id') + assert len(list_data[0]['_id']) == 24 def test_disable_live_agent(self): processor = MongoProcessor() @@ -3565,7 +3585,7 @@ def _mock_bot_info(*args, **kwargs): def test_download_data_files_with_actions(self, monkeypatch): from zipfile import ZipFile - expected_actions = b'database_action: []\nemail_action: []\nform_validation_action: []\ngoogle_search_action: []\nhttp_action: []\njira_action: []\npipedrive_leads_action: []\nprompt_action: []\npyscript_action: []\nrazorpay_action: []\nslot_set_action: []\ntwo_stage_fallback: []\nzendesk_action: []\n'.decode( + expected_actions = b'database_action: []\nemail_action: []\nform_validation_action: []\ngoogle_search_action: []\nhttp_action: []\njira_action: []\nlive_agent_action: []\npipedrive_leads_action: []\nprompt_action: []\npyscript_action: []\nrazorpay_action: []\nslot_set_action: []\ntwo_stage_fallback: []\nzendesk_action: []\n'.decode( encoding='utf-8') def _mock_bot_info(*args, **kwargs): @@ -3602,7 +3622,7 @@ def test_load_action_configurations(self): assert action_config == {'http_action': [], 'jira_action': [], 'email_action': [], 'zendesk_action': [], 'form_validation_action': [], 'slot_set_action': [], 'google_search_action': [], 'pipedrive_leads_action': [], 'two_stage_fallback': [], 'prompt_action': [], - 'razorpay_action': [], 'pyscript_action': [], 'database_action': []} + 'razorpay_action': [], 'pyscript_action': [], 'database_action': [], 'live_agent_action': []} def test_get_utterance_from_intent(self): processor = MongoProcessor()