diff --git a/daras_ai_v2/bots.py b/daras_ai_v2/bots.py index f26ba9548..fb484339d 100644 --- a/daras_ai_v2/bots.py +++ b/daras_ai_v2/bots.py @@ -268,6 +268,7 @@ def send_msg( update_msg_id=update_msg_id, ) text = "" + update_msg_id = None if send_feedback_buttons: buttons = _feedback_buttons() diff --git a/daras_ai_v2/slack_bot.py b/daras_ai_v2/slack_bot.py index 6e1e4b571..147b3b60a 100644 --- a/daras_ai_v2/slack_bot.py +++ b/daras_ai_v2/slack_bot.py @@ -685,3 +685,67 @@ class SlackAPIError(Exception): def __init__(self, error: str | dict): self.error = error super().__init__(error) + + +def update_msg_acknowledge_selection( + *, + channel: str, + ts: str, + token: str, + original_blocks: list[dict] | None, + original_text: str | None, + selection_text: str | None, +): + """ + Remove any action (button) blocks from the message and append a small italic + context line acknowledging the user's selection. Preserves the rest of the blocks. + """ + original_blocks = original_blocks or [] + new_blocks = [b for b in original_blocks if b.get("type") != "actions"] + if selection_text: + new_blocks.append( + { + "type": "context", + "elements": [ + {"type": "mrkdwn", "text": f"_You chose: {selection_text}_"}, + ], + } + ) + res = requests.post( + "https://slack.com/api/chat.update", + json={ + "channel": channel, + "ts": ts, + "text": original_text or "", + "blocks": new_blocks, + }, + headers={"Authorization": f"Bearer {token}"}, + ) + parse_slack_response(res) + + +def update_msg_ack_selection_from_payload(payload: dict): + """ + Convenience helper to process a Slack block_actions payload and update the + original message by removing buttons and appending an italic confirmation. + Performs BotIntegration lookup internally to get the token. + """ + from bots.models import BotIntegration + + channel_id = payload["channel"]["id"] + team_id = payload["team"]["id"] + message_ts = payload["container"]["message_ts"] + action = payload["actions"][0] + action_title = (action.get("text", {}) or {}).get("text") or "" + original_blocks = (payload.get("message", {}) or {}).get("blocks", []) or [] + original_text = (payload.get("message", {}) or {}).get("text") or "" + + bi = BotIntegration.objects.get(slack_channel_id=channel_id, slack_team_id=team_id) + update_msg_acknowledge_selection( + channel=channel_id, + ts=message_ts, + token=bi.slack_access_token, + original_blocks=original_blocks, + original_text=original_text, + selection_text=action_title, + ) diff --git a/routers/slack_api.py b/routers/slack_api.py index bbc11e195..2e8654f4d 100644 --- a/routers/slack_api.py +++ b/routers/slack_api.py @@ -35,6 +35,7 @@ SlackAPIError, fetch_user_info, parse_slack_response, + update_msg_ack_selection_from_payload, ) from routers.custom_api_router import CustomAPIRouter from workspaces.widgets import get_current_workspace @@ -171,6 +172,11 @@ def slack_interaction( raise HTTPException(403, "Only accepts requests from Slack") if data["type"] != "block_actions": return + # Immediately update the original message to remove buttons and show selection + try: + update_msg_ack_selection_from_payload(data) + except Exception as e: + capture_exception(e) bot = SlackBot( message_ts=data["container"]["message_ts"], team_id=data["team"]["id"], @@ -226,8 +232,6 @@ def _handle_slack_event(event: dict, background_tasks: BackgroundTasks): return files = message.get("files", []) - if not files: - message.get("message", {}).get("files", []) if not files: attachments = message.get("attachments", []) files = [