Immediate Mark Resolved SlackBot Option and Respond to Bots Option (#1031)

This commit is contained in:
Yuhong Sun 2024-02-01 22:18:15 -08:00 committed by GitHub
parent 29e74c0877
commit 0060a1dd58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 82 additions and 22 deletions

View File

@ -20,6 +20,7 @@ from danswer.danswerbot.slack.constants import DISLIKE_BLOCK_ACTION_ID
from danswer.danswerbot.slack.constants import FEEDBACK_DOC_BUTTON_BLOCK_ACTION_ID
from danswer.danswerbot.slack.constants import FOLLOWUP_BUTTON_ACTION_ID
from danswer.danswerbot.slack.constants import FOLLOWUP_BUTTON_RESOLVED_ACTION_ID
from danswer.danswerbot.slack.constants import IMMEDIATE_RESOLVED_BUTTON_ACTION_ID
from danswer.danswerbot.slack.constants import LIKE_BLOCK_ACTION_ID
from danswer.danswerbot.slack.utils import build_feedback_id
from danswer.danswerbot.slack.utils import remove_slack_text_interactions
@ -279,11 +280,16 @@ def build_follow_up_block(message_id: int | None) -> ActionsBlock:
return ActionsBlock(
block_id=build_feedback_id(message_id) if message_id is not None else None,
elements=[
ButtonElement(
action_id=IMMEDIATE_RESOLVED_BUTTON_ACTION_ID,
style="primary",
text="I'm all set!",
),
ButtonElement(
action_id=FOLLOWUP_BUTTON_ACTION_ID,
style="danger",
text="I need more help from a human!",
)
),
],
)

View File

@ -1,6 +1,7 @@
LIKE_BLOCK_ACTION_ID = "feedback-like"
DISLIKE_BLOCK_ACTION_ID = "feedback-dislike"
FEEDBACK_DOC_BUTTON_BLOCK_ACTION_ID = "feedback-doc-button"
IMMEDIATE_RESOLVED_BUTTON_ACTION_ID = "immediate-resolved-button"
FOLLOWUP_BUTTON_ACTION_ID = "followup-button"
FOLLOWUP_BUTTON_RESOLVED_ACTION_ID = "followup-resolved-button"
SLACK_CHANNEL_ID = "channel_id"

View File

@ -192,14 +192,11 @@ def handle_followup_button(
)
def handle_followup_resolved_button(
def get_clicker_name(
req: SocketModeRequest,
client: SocketModeClient,
) -> None:
channel_id = req.payload["container"]["channel_id"]
message_ts = req.payload["container"]["message_ts"]
thread_ts = req.payload["container"]["thread_ts"]
clicker_backup_name = req.payload.get("user", {}).get("name", "Someone")
) -> str:
clicker_name = req.payload.get("user", {}).get("name", "Someone")
clicker_real_name = None
try:
clicker = client.web_client.users_info(user=req.payload["user"]["id"])
@ -210,6 +207,23 @@ def handle_followup_resolved_button(
# Likely a scope issue
pass
if clicker_real_name:
clicker_name = clicker_real_name
return clicker_name
def handle_followup_resolved_button(
req: SocketModeRequest,
client: SocketModeClient,
immediate: bool = False,
) -> None:
channel_id = req.payload["container"]["channel_id"]
message_ts = req.payload["container"]["message_ts"]
thread_ts = req.payload["container"]["thread_ts"]
clicker_name = get_clicker_name(req, client)
update_emote_react(
emoji=DANSWER_FOLLOWUP_EMOJI,
channel=channel_id,
@ -218,20 +232,27 @@ def handle_followup_resolved_button(
client=client.web_client,
)
slack_call = make_slack_api_rate_limited(client.web_client.chat_delete)
response = slack_call(
channel=channel_id,
ts=message_ts,
)
# Delete the message with the option to mark resolved
if not immediate:
slack_call = make_slack_api_rate_limited(client.web_client.chat_delete)
response = slack_call(
channel=channel_id,
ts=message_ts,
)
if not response.get("ok"):
logger_base.error("Unable to delete message for resolved")
if not response.get("ok"):
logger_base.error("Unable to delete message for resolved")
resolved_block = SectionBlock(
text=f"{clicker_real_name or clicker_backup_name} has marked this question as resolved! "
f'\n\n You can always click the "I need more help button" to let the team '
f"know that your problem still needs attention."
)
if immediate:
msg_text = f"{clicker_name} has marked this question as resolved!"
else:
msg_text = (
f"{clicker_name} has marked this question as resolved! "
f'\n\n You can always click the "I need more help button" to let the team '
f"know that your problem still needs attention."
)
resolved_block = SectionBlock(text=msg_text)
respond_in_thread(
client=client.web_client,

View File

@ -19,6 +19,7 @@ from danswer.danswerbot.slack.constants import DISLIKE_BLOCK_ACTION_ID
from danswer.danswerbot.slack.constants import FEEDBACK_DOC_BUTTON_BLOCK_ACTION_ID
from danswer.danswerbot.slack.constants import FOLLOWUP_BUTTON_ACTION_ID
from danswer.danswerbot.slack.constants import FOLLOWUP_BUTTON_RESOLVED_ACTION_ID
from danswer.danswerbot.slack.constants import IMMEDIATE_RESOLVED_BUTTON_ACTION_ID
from danswer.danswerbot.slack.constants import LIKE_BLOCK_ACTION_ID
from danswer.danswerbot.slack.constants import SLACK_CHANNEL_ID
from danswer.danswerbot.slack.constants import VIEW_DOC_FEEDBACK_ID
@ -87,8 +88,20 @@ def prefilter_requests(req: SocketModeRequest, client: SocketModeClient) -> bool
return False
if event.get("bot_profile"):
channel_specific_logger.info("Ignoring message from bot")
return False
channel_name, _ = get_channel_name_from_id(
client=client.web_client, channel_id=channel
)
engine = get_sqlalchemy_engine()
with Session(engine) as db_session:
slack_bot_config = get_slack_bot_config_for_channel(
channel_name=channel_name, db_session=db_session
)
if not slack_bot_config or not slack_bot_config.channel_config.get(
"respond_to_bots"
):
channel_specific_logger.info("Ignoring message from bot")
return False
# Ignore things like channel_join, channel_leave, etc.
# NOTE: "file_share" is just a message with a file attachment, so we
@ -300,8 +313,10 @@ def action_routing(req: SocketModeRequest, client: SocketModeClient) -> None:
return handle_doc_feedback_button(req, client)
elif action["action_id"] == FOLLOWUP_BUTTON_ACTION_ID:
return handle_followup_button(req, client)
elif action["action_id"] == IMMEDIATE_RESOLVED_BUTTON_ACTION_ID:
return handle_followup_resolved_button(req, client, immediate=True)
elif action["action_id"] == FOLLOWUP_BUTTON_RESOLVED_ACTION_ID:
return handle_followup_resolved_button(req, client)
return handle_followup_resolved_button(req, client, immediate=False)
def view_routing(req: SocketModeRequest, client: SocketModeClient) -> None:

View File

@ -786,6 +786,7 @@ class ChannelConfig(TypedDict):
channel_names: list[str]
respond_tag_only: NotRequired[bool] # defaults to False
respond_to_bots: NotRequired[bool] # defaults to False
respond_team_member_list: NotRequired[list[str]]
answer_filters: NotRequired[list[AllowedAnswerFilters]]
# If None then no follow up

View File

@ -75,6 +75,7 @@ class SlackBotConfigCreationRequest(BaseModel):
persona_id: int | None # NOTE: only one of `document_sets` / `persona_id` should be set
channel_names: list[str]
respond_tag_only: bool = False
respond_to_bots: bool = False
# If no team members, assume respond in the channel to everyone
respond_team_member_list: list[str] = []
answer_filters: list[AllowedAnswerFilters] = []

View File

@ -77,6 +77,10 @@ def _form_channel_config(
if follow_up_tags is not None:
channel_config["follow_up_tags"] = follow_up_tags
channel_config[
"respond_to_bots"
] = slack_bot_config_creation_request.respond_to_bots
return channel_config

View File

@ -69,6 +69,8 @@ export const SlackBotCreationForm = ({
).includes("questionmark_prefilter"),
respond_tag_only:
existingSlackBotConfig?.channel_config?.respond_tag_only || false,
respond_to_bots:
existingSlackBotConfig?.channel_config?.respond_to_bots || false,
respond_team_member_list:
existingSlackBotConfig?.channel_config
?.respond_team_member_list || ([] as string[]),
@ -94,6 +96,7 @@ export const SlackBotCreationForm = ({
answer_validity_check_enabled: Yup.boolean().required(),
questionmark_prefilter_enabled: Yup.boolean().required(),
respond_tag_only: Yup.boolean().required(),
respond_to_bots: Yup.boolean().required(),
respond_team_member_list: Yup.array().of(Yup.string()).required(),
still_need_help_enabled: Yup.boolean().required(),
follow_up_tags: Yup.array().of(Yup.string()),
@ -187,6 +190,11 @@ export const SlackBotCreationForm = ({
label="Respond to @DanswerBot Only"
subtext="If set, DanswerBot will only respond when directly tagged"
/>
<BooleanFormField
name="respond_to_bots"
label="Responds to Bot messages"
subtext="If not set, DanswerBot will always ignore messages from Bots"
/>
<TextArrayField
name="respond_team_member_list"
label="Team Members Emails"

View File

@ -8,6 +8,7 @@ interface SlackBotConfigCreationRequest {
answer_validity_check_enabled: boolean;
questionmark_prefilter_enabled: boolean;
respond_tag_only: boolean;
respond_to_bots: boolean;
respond_team_member_list: string[];
follow_up_tags?: string[];
usePersona: boolean;
@ -32,6 +33,7 @@ const buildRequestBodyFromCreationRequest = (
return JSON.stringify({
channel_names: creationRequest.channel_names,
respond_tag_only: creationRequest.respond_tag_only,
respond_to_bots: creationRequest.respond_to_bots,
respond_team_member_list: creationRequest.respond_team_member_list,
answer_filters: buildFiltersFromCreationRequest(creationRequest),
follow_up_tags: creationRequest.follow_up_tags?.filter((tag) => tag !== ""),

View File

@ -351,6 +351,7 @@ export type AnswerFilterOption =
export interface ChannelConfig {
channel_names: string[];
respond_tag_only?: boolean;
respond_to_bots?: boolean;
respond_team_member_list?: string[];
answer_filters?: AnswerFilterOption[];
follow_up_tags?: string[];