Skip to content

Commit

Permalink
Live agent (#1193)
Browse files Browse the repository at this point in the history
* rasa 3.6 upgrade

* changed pymupdf

* fixed docker anf gitlabci

* added prod and dev requirements

* fixed requirements

* removed mock stores

* add pip upgrade

* added folder creation with parents folder

* added docker system cleanup

* fixed validate prompts test case

* added kairon version 3 docker

* fix kairon base tag

* added models in base image for nltk, spacy

* fixed setupfiles

* removed virtual env

* fix step in gitlab

* python version in setup.sh

* gitlab ci corrected

* gitlab ci corrected

* pyssl issue fixed

* added virtual env with caching

* added pip upgrade in venv

* web search action merged

* event server changes

* added elastic search as dependency

* fixed action server issue

* optmised docker image

* test fixed for ujson

* merge chatserver and pyscript action

* fixed kairon LanguageModelFeaturizer

* merged master changes

* optmised docker to improve build and push time

* evaluator service corrected

* changed debug log to error

* added timeout for chat and action server

* added timeout for chat and action server

* added environment variable for chat and action server for timeout

* 1. added default config for kairon rule policy
2. added granian for action and chat server
3. added error log level for action and chat server

* 1. added default config for kairon rule policy
2. added granian for action and chat server

* fix multi-flow stories

* 1. fix action test
2. actor version
3. fix get request for external api

* add channel changes

* changed the name of kairon rule policy to KRulePolicy

* xray removed

* removed kairon KRulePolicy

* test cases fixed

* test cases fixed

* removed constrain_similarities

* moved kairon RulePolicy from base to chatserver

* changes tracker condition

* merged event db changes for db server

* added pyston

* email error fixed

* fix kairon history saving issue

* removed pyston from test pipeline

* base image version fix

* updated rasa version

* added meta data in tracker events

* fix form action not running

* added entities to slot autofill

* fix auto-fill feature for slots

* 1. form fixes

* hard delete for bot data.

* 1. added granian
2 added default tab

* build corected

* library updated

* removed granian

* form fix

* fixed test failures due to merge conflicts

* fixed test failures due to merge conflicts

* when intent is deleted then all the respected training example must be deleted

* test case fixed

* added asynccontext manager startup and shutdown event deprecated

* Fixed - All stories are getting converted to QnA after file upload.
1. Changed the logic of get_template_type function to retrieve the template type.
2. Fixed test cases.

* allow adding conditions to slot mappings and filter slot mappings attached to form

* change slack to slack_sdk deprecated

* changed the default port 8083 to somthing random

* apm turn off for services

* test case fixed for apm client

* test case fixed for apm client

* lifespan fixed for fastapi

* fixed test failure

* added dependency and fixed test failures

* Modified get_slot_mappings function.

* 1. added deprecated components for config
2. updated rasa and other libraries

* removed versions for domain.yml

* fix for add bot data in prod

* dependencies updated

* merged the prod changes

* library updated

* removed default path parameter and added google my business dependency

Co-authored-by: udit-pandey <[email protected]>
Co-authored-by: nupur-khare <[email protected]>

* fixed test failures post code merge from master

* added json support for pyscript action

* added json support for pyscript action

* Fixed - onboarding not working on new uat.
Changed domain.yml's path

* Upload & Download -> Database Action.

* Modified moto version in requirements.txt

* Modified moto version in requirements.txt and dev.txt

* Multiple parameters/collections in prompt action.
1. Gave prompt-specific hyperparameters, collection top_results, and similarity_threshold.
2. Added unit and integration test cases.
3. Fixed test cases.

* kairon 2.x changes merged in 3.x

* kairon 2.x changes merged in 3.x

* log level fixed

* log level fixed

* on boarding fix

* added test case for copy pretrained model

* kernel security fix

* onboarding fix

* onboarding fix test cases

* onboarding fix test cases

* 1. updated open ai embedding model
2. added security fix for amazonlinux

* removed docker build stage

* Fixed the download chat history issue on New UAT.

* Fixed the download chat history issue on New UAT and fixed the test case.

* download history fixed

* moved to single docker image

* history download fix

* removed force from gitlab pipeline

* changes in linkedin scope

* fixed chat test cases

* fixed chat test cases

* Gpt fix.

* fixed chat test cases

* gitlab ci stages removed

* removed release docker build

* prod changes merged

* updated rasa 3.6.18

* 1. added open telemetry
2. updated rasa to 3.6.19

* otel bootstrap corrected

* downgraded otel dude to dependencies issue

* packaging updated

* downgraded packing version

* added instrumentation for cli

* Line integration (#1158)

* tempurary commit

* Line platform integration

* removed unnecessary imports

---------

Co-authored-by: spandan.mondal <[email protected]>

* added only required library for instrumentation

* Fixed load model exception issue and fixed test cases. (#1159)

Co-authored-by: Mahesh <[email protected]>

* merged changes from production

* http action logs

* removed unidentifying resources

* Fixed Prompt action

* removed unidentifying resources

* Fixed Prompt action

* info logging for linkedin sso

* info logging for linkedin sso

* - removing 'run_async' as its no more required by rasa SDK

* Added default date range of 6 months for the trends APIs and made changes in aggregation pipeline for few APIs and fixed test cases. (#1167)

Co-authored-by: Mahesh <[email protected]>

* linkedin sso fix

* info logging for linkedin sso

* info logging for linkedin sso

* linkedin sso fix

* - removing 'run_async' as its no more required by rasa SDK

* - removing await for slack

* - Added link in template as dynamic link

* - Added link in template as dynamic link

* Prevent Any Slot (#1169)

* Added validation to prevent the slot with any type while adding or updating the form.

* Added validation to prevent the slot with any type while adding or updating the form.

---------

Co-authored-by: Mahesh <[email protected]>

* model training issue fixed

* fixed docker vulnerabilities

* fixed docker vulnerabilities

* live agent

* 1. added model train in Dockerfile
2. add the logic to handle flag for similarity prompt

* added logger for timestamp validation for history

* DB Action with user msg (#1176)

* db action query with user message and added and fixed few test cases.

* db action query with user message and added and fixed few test cases.

* db action query with user message and added and fixed few test cases.

* Added llm_settings validation while creating and updating the db_action.

---------

Co-authored-by: Mahesh <[email protected]>

* Slot mapping normalization (#1179)

Co-authored-by: spandan.mondal <[email protected]>

* changed tester roles for configure nudge and configure telemetry. (#1178)

Co-authored-by: Mahesh <[email protected]>

* fixed issue related to security

* fixed from_date issue on analytics api

* fixed from_date issue on analytics api

* Removed validation for the payload value while creating the db action (#1181)

Co-authored-by: Mahesh <[email protected]>

* fixed issue related to security

* Upload with Prompt Action (#1182)

* Fixed the validation issue for prompt action while uploading the files.

* Fixed the validation issue for prompt action while uploading the files.

* Added test cases for the prompt action with bot_content as source.

---------

Co-authored-by: Mahesh <[email protected]>

* fixed issue related to security

* Prompt Action response time (#1186)

* Added response time for the prompt action and fixed test cases

* Added response time for the prompt action and fixed test cases

---------

Co-authored-by: Mahesh <[email protected]>

* 1. rasa version updated
2. added single day for test script generation

* test cases fixed

* live agent integration

* live agent integration

* removed default bot in kairon

* live agent integration

* light agent -small changes

* light agent -small changes -part 2

* light agent -small changes -part 3

* light agent -code cleanup

* code cleanup

* code cleanup

* code cleanup

* code cleanup

* test case fixes

* test case fixes

* test case fixes

---------

Co-authored-by: Fahad Ali Shaikh <[email protected]>
Co-authored-by: udit_pandey <[email protected]>
Co-authored-by: Nupur Khare <[email protected]>
Co-authored-by: Udit Pandey <[email protected]>
Co-authored-by: nupur-khare <[email protected]>
Co-authored-by: Mahesh <[email protected]>
Co-authored-by: hghuge <[email protected]>
Co-authored-by: spandan.mondal <[email protected]>
Co-authored-by: maheshsattala <[email protected]>
Co-authored-by: sushantpatade <[email protected]>
  • Loading branch information
11 people authored May 8, 2024
1 parent ec91510 commit 5dc2c49
Show file tree
Hide file tree
Showing 29 changed files with 1,170 additions and 220 deletions.
4 changes: 3 additions & 1 deletion kairon/actions/definitions/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from kairon.actions.definitions.http import ActionHTTP
from kairon.actions.definitions.hubspot import ActionHubspotForms
from kairon.actions.definitions.jira import ActionJiraTicket
from kairon.actions.definitions.live_agent import ActionLiveAgent
from kairon.actions.definitions.pipedrive import ActionPipedriveLeads
from kairon.actions.definitions.prompt import ActionPrompt
from kairon.actions.definitions.pyscript import ActionPyscript
Expand Down Expand Up @@ -39,7 +40,8 @@ class ActionFactory:
ActionType.prompt_action.value: ActionPrompt,
ActionType.pyscript_action.value: ActionPyscript,
ActionType.database_action.value: ActionDatabase,
ActionType.web_search_action.value: ActionWebSearch
ActionType.web_search_action.value: ActionWebSearch,
ActionType.live_agent_action.value: ActionLiveAgent
}

@staticmethod
Expand Down
110 changes: 110 additions & 0 deletions kairon/actions/definitions/live_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from typing import Text, Dict, Any

from loguru import logger
from mongoengine import DoesNotExist
from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher

from kairon.actions.definitions.base import ActionsBase
from kairon.shared.actions.data_objects import ActionServerLogs, LiveAgentActionConfig
from kairon.shared.actions.exception import ActionFailure
from kairon.shared.actions.models import ActionType, DispatchType
from kairon.shared.actions.utils import ActionUtility
from kairon.shared.live_agent.live_agent import LiveAgentHandler
from kairon.shared.constants import ChannelTypes


CONST_CHANNEL_NAME_MAP = {
'TelegramHandler': ChannelTypes.TELEGRAM.value,
'facebook': ChannelTypes.MESSENGER.value,
'instagram': ChannelTypes.INSTAGRAM.value,
'whatsapp': ChannelTypes.WHATSAPP.value,
}


class ActionLiveAgent(ActionsBase):

def __init__(self, bot: Text, name: Text):
"""
Initialize HTTP action.
@param bot: bot id
@param name: action name
"""
self.bot = bot
self.name = 'live_agent_action'
self.__response = None
self.__is_success = False

def retrieve_config(self):
"""
Fetch LiveAgentAction configuration parameters from the database
:return: HttpActionConfig containing configuration for the action as a dict.
"""
try:
live_agent_config_dict = LiveAgentActionConfig.objects().get(bot=self.bot,
name=self.name, status=True).to_mongo().to_dict()
logger.debug("live_agent_action_config: " + str(live_agent_config_dict))
return live_agent_config_dict
except DoesNotExist as e:
logger.exception(e)
raise ActionFailure("No Live Agent action found for given action and bot")

async def execute(self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]):
"""
Retrieves action config and executes it.
Information regarding the execution is logged in ActionServerLogs.
@param dispatcher: Client to send messages back to the user.
@param tracker: Tracker object to retrieve slots, events, messages and other contextual information.
@param domain: Bot domain
:return: Dict containing slot name as keys and their values.
"""
bot_response = None
exception = None
filled_slots = {}
dispatch_bot_response = True
status = "SUCCESS"
msg_logger = []

try:
action_config = self.retrieve_config()
dispatch_bot_response = action_config.get('dispatch_bot_response', True)
bot_response = action_config.get('bot_response')
channel = CONST_CHANNEL_NAME_MAP[tracker.get_latest_input_channel()]
await LiveAgentHandler.request_live_agent(self.bot, tracker.sender_id, channel)
self.__is_success = True
self.__response = bot_response
except Exception as e:
exception = e
self.__is_success = False
logger.exception(e)
status = "FAILURE"
bot_response = bot_response if bot_response else "Sorry, I am unable to process your request at the moment."
finally:
if dispatch_bot_response:
bot_response, message = ActionUtility.handle_utter_bot_response(dispatcher, DispatchType.text.value, bot_response)
if message:
msg_logger.append(message)
ActionServerLogs(
type=ActionType.live_agent_action.value,
intent=tracker.get_intent_of_latest_message(skip_fallback_intent=False),
action=self.name,
sender=tracker.sender_id,
bot_response=str(bot_response) if bot_response else None,
messages=msg_logger,
exception=str(exception) if exception else None,
bot=self.bot,
status=status,
user_msg=tracker.latest_message.get('text')
).save()
return filled_slots

@property
def is_success(self):
return self.__is_success

@property
def response(self):
return self.__response
45 changes: 44 additions & 1 deletion kairon/api/app/routers/bot/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
HttpActionConfigRequest, SlotSetActionRequest, EmailActionRequest, GoogleSearchActionRequest, JiraActionRequest,
ZendeskActionRequest, PipedriveActionRequest, HubspotFormsActionRequest, TwoStageFallbackConfigRequest,
RazorpayActionRequest, PromptActionConfigRequest, DatabaseActionRequest, PyscriptActionRequest,
WebSearchActionRequest
WebSearchActionRequest, LiveAgentActionRequest
)
from kairon.shared.constants import TESTER_ACCESS, DESIGNER_ACCESS
from kairon.shared.models import User
Expand Down Expand Up @@ -559,3 +559,46 @@ async def update_razorpay_action(
"""
mongo_processor.edit_razorpay_action(request_data.dict(), current_user.get_bot(), current_user.get_user())
return Response(message="Action updated!")


@router.get("/live_agent", response_model=Response)
async def get_live_agent(
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS)
):
"""
Returns configuration for live agent action.
"""
config = mongo_processor.get_live_agent(current_user.get_bot())
return Response(data=config)


@router.post("/live_agent", response_model=Response)
async def enable_live_agent(
request_data: LiveAgentActionRequest,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS)
):
status = mongo_processor.enable_live_agent(request_data.dict(), current_user.get_bot(), current_user.get_user())
msg = "Live Agent Action enabled!" if status else "Live Agent Action already enabled!"
return Response(message=msg)


@router.put("/live_agent", response_model=Response)
async def update_live_agent(
request_data: LiveAgentActionRequest,
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS)
):
"""
Updates the live agent action config.
"""

mongo_processor.edit_live_agent(request_data.dict(), current_user.get_bot(), current_user.get_user())
return Response(message="Action updated!")


@router.get("/live_agent/disable", response_model=Response)
async def disable_live_agent(
current_user: User = Security(Authentication.get_current_user_and_bot, scopes=DESIGNER_ACCESS)
):
mongo_processor.disable_live_agent(current_user.get_bot())
return Response(message="Live Agent Action disabled!")

14 changes: 13 additions & 1 deletion kairon/api/app/routers/bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from kairon.shared.actions.data_objects import ActionServerLogs
from kairon.shared.auth import Authentication
from kairon.shared.constants import TESTER_ACCESS, DESIGNER_ACCESS, CHAT_ACCESS, UserActivityType, ADMIN_ACCESS, \
VIEW_ACCESS, EventClass
VIEW_ACCESS, EventClass, AGENT_ACCESS
from kairon.shared.data.assets_processor import AssetsProcessor
from kairon.shared.data.audit.processor import AuditDataProcessor
from kairon.shared.data.constant import EVENT_STATUS, ENDPOINT_TYPE, TOKEN_TYPE, ModelTestType, \
Expand All @@ -41,6 +41,8 @@
from kairon.shared.models import User, TemplateType
from kairon.shared.test.processor import ModelTestingLogProcessor
from kairon.shared.utils import Utility
from kairon.shared.live_agent.live_agent import LiveAgentHandler


router = APIRouter()
v2 = APIRouter()
Expand Down Expand Up @@ -1655,3 +1657,13 @@ async def update_bot_settings(
"""Updates bot settings"""
MongoProcessor.edit_bot_settings(bot_settings.dict(), current_user.get_bot(), current_user.get_user())
return Response(message='Bot Settings updated')


@router.get("/live_agent_token", response_model=Response)
async def get_live_agent_token(current_user: User = Security(Authentication.get_current_user_and_bot, scopes=AGENT_ACCESS)):
"""
Fetches existing list of stories (conversation flows)
"""
data = await LiveAgentHandler.authenticate_agent(current_user.get_user(), current_user.get_bot())
return Response(data=data)

5 changes: 5 additions & 0 deletions kairon/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ def validate_collection_name(cls, v, values, **kwargs):
return v


class LiveAgentActionRequest(BaseModel):
bot_response: str = "connecting to live agent"
dispatch_bot_response: bool = True


class TrainingData(BaseModel):
intent: constr(to_lower=True, strip_whitespace=True)
training_examples: List[str]
Expand Down
11 changes: 10 additions & 1 deletion kairon/chat/agent_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

from loguru import logger as logging
from rasa.core.agent import Agent
from rasa.core.channels import UserMessage

from kairon.shared.chat.cache.in_memory_agent import AgentCache
from kairon.exceptions import AppException
from kairon.shared.data.processor import MongoProcessor
from .agent.agent import KaironAgent
from kairon.shared.chat.cache.in_memory_agent import InMemoryAgentCache
from ..shared.live_agent.live_agent import LiveAgentHandler
from ..shared.utils import Utility
from kairon.shared.otel import record_custom_attributes

Expand All @@ -32,7 +34,6 @@ def get_agent(bot: Text) -> Agent:
"""
if not AgentProcessor.cache_provider.is_exists(bot) or not AgentProcessor.is_latest_version_in_mem(bot):
AgentProcessor.reload(bot)

record_custom_attributes(num_models=AgentProcessor.cache_provider.len())
return AgentProcessor.cache_provider.get(bot)

Expand Down Expand Up @@ -69,3 +70,11 @@ def is_latest_version_in_mem(bot: Text):
in_mem_model_ver = AgentProcessor.cache_provider.get(bot).model_ver
logging.debug(f"PID:{os.getpid()} In memory model:{in_mem_model_ver}, latest trained model:{latest_ver}")
return latest_ver == in_mem_model_ver

@staticmethod
async def handle_channel_message(bot: Text, userdata: UserMessage):
is_live_agent_enabled = await LiveAgentHandler.check_live_agent_active(bot, userdata)
logging.debug(f"Live agent enabled:{is_live_agent_enabled}")
if not is_live_agent_enabled:
return await AgentProcessor.get_agent(bot).handle_message(userdata)
return await LiveAgentHandler.process_live_agent(bot, userdata)
3 changes: 2 additions & 1 deletion kairon/chat/handlers/channels/messenger.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ async def _handle_user_message(

@staticmethod
async def process_message(bot: str, user_message: UserMessage):
await AgentProcessor.get_agent(bot).handle_message(user_message)
await AgentProcessor.handle_channel_message(bot, user_message)
#await AgentProcessor.get_agent(bot).handle_message(user_message)


class MessengerBot(OutputChannel):
Expand Down
2 changes: 1 addition & 1 deletion kairon/chat/handlers/channels/msteams.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ def is_validate_hash(request: Request):
jwt_token = Utility.decrypt_message(secrettoken)
return secrethash == token, jwt_token

async def validate(self) :
async def validate(self):
return {"status": "ok"}

async def handle_message(self):
Expand Down
2 changes: 1 addition & 1 deletion kairon/chat/handlers/channels/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ async def handle_message(self):

@staticmethod
async def process_message(bot: str, user_message: UserMessage):
await AgentProcessor.get_agent(bot).handle_message(user_message)
await AgentProcessor.handle_channel_message(bot, user_message)

@staticmethod
def get_output_channel(access_token, webhook_url) -> TelegramOutput:
Expand Down
2 changes: 1 addition & 1 deletion kairon/chat/handlers/channels/whatsapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ async def _handle_user_message(

@staticmethod
async def process_message(bot: str, user_message: UserMessage):
await AgentProcessor.get_agent(bot).handle_message(user_message)
await AgentProcessor.handle_channel_message(bot, user_message)

def __get_access_token(self):
provider = self.config.get("bsp_type", "meta")
Expand Down
6 changes: 6 additions & 0 deletions kairon/chat/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,12 @@ def __get_metadata(
metadata.update(default_metadata)
return metadata







@staticmethod
def add_telemetry_metadata(x_telemetry_uid: Text, x_telemetry_sid: Text, metadata: Dict = None):
if not metadata:
Expand Down
27 changes: 27 additions & 0 deletions kairon/shared/actions/data_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -854,3 +854,30 @@ def clean(self):
signals.pre_save_post_validation.connect(
HttpActionConfig.pre_save_post_validation, sender=HttpActionConfig
)


@auditlogger.log
@push_notification.apply
class LiveAgentActionConfig(Auditlog):
name = StringField(default='live_agent_action')
bot_response = StringField(default='Connecting to live agent')
dispatch_bot_response = BooleanField(default=True)
bot = StringField(required=True)
user = StringField(required=True)
timestamp = DateTimeField(default=datetime.utcnow)
status = BooleanField(default=True)

meta = {"indexes": [{"fields": ["bot", ("bot", "action_name", "status")]}]}

def validate(self, clean=True):
if clean:
self.clean()

def clean(self):
self.name = self.name.strip().lower()
if Utility.check_empty_string(self.name):
raise ValidationError("Action name cannot be empty or blank spaces")
if self.name.startswith("utter_"):
raise ValidationError("Action name cannot start with utter_")


1 change: 1 addition & 0 deletions kairon/shared/actions/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class ActionType(str, Enum):
pyscript_action = "pyscript_action"
database_action = "database_action"
web_search_action = "web_search_action"
live_agent_action = "live_agent_action"


class HttpRequestContentType(str, Enum):
Expand Down
6 changes: 5 additions & 1 deletion kairon/shared/chat/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ def save_channel_config(configuration: Dict, bot: Text, user: Text):
filter_args = ChatDataProcessor.__attach_metadata_and_get_filter(configuration, bot)
channel = Channels.objects(**filter_args).get()
channel.config = configuration['config']
primary_slack_config_changed = True if channel.connector_type == 'slack' and channel.config.get('is_primary') else False
primary_slack_config_changed = True if channel.connector_type == 'slack' and channel.config.get(
'is_primary') else False
except DoesNotExist:
channel = Channels(**configuration)
channel.bot = bot
Expand All @@ -55,6 +56,9 @@ def __attach_metadata_and_get_filter(configuration: Dict, bot: Text):
filter_args["config__team__id"] = configuration['config']['team']['id']
return filter_args

def __getattribute__(self, __name):
return super().__getattribute__(__name)

@staticmethod
def delete_channel_config(bot: Text, **kwargs):
"""
Expand Down
3 changes: 3 additions & 0 deletions kairon/shared/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

VIEW_ACCESS = [ACCESS_ROLES.OWNER.value, ACCESS_ROLES.ADMIN.value, ACCESS_ROLES.DESIGNER.value, ACCESS_ROLES.TESTER.value, ACCESS_ROLES.CHAT.value, ACCESS_ROLES.VIEW.value]

AGENT_ACCESS = [ACCESS_ROLES.OWNER.value, ACCESS_ROLES.ADMIN.value, ACCESS_ROLES.DESIGNER.value, ACCESS_ROLES.TESTER.value, ACCESS_ROLES.CHAT.value, ACCESS_ROLES.VIEW.value, ACCESS_ROLES.AGENT.value]


KAIRON_USER_MSG_ENTITY = "kairon_user_msg"

FAQ_DISABLED_ERR = "Faq feature is disabled for the bot! Please contact support."
Expand Down
1 change: 1 addition & 0 deletions kairon/shared/data/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class ACCESS_ROLES(str, Enum):
TESTER = "tester"
CHAT = "chat"
VIEW = "view"
AGENT = "agent"


class ACTIVITY_STATUS(str, Enum):
Expand Down
Loading

0 comments on commit 5dc2c49

Please sign in to comment.