Skip to content
This repository was archived by the owner on Sep 3, 2025. It is now read-only.
Merged
4 changes: 2 additions & 2 deletions src/dispatch/ai/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ def generate_read_in_summary(
return ReadInSummaryResponse(error_message=message)

conversation = conversation_plugin.instance.get_conversation(
conversation_id=channel_id, important_reaction=important_reaction
conversation_id=channel_id, include_user_details=True, important_reaction=important_reaction
)
if not conversation:
message = f"Read-in summary not generated for {subject.name}. No conversation found."
Expand Down Expand Up @@ -739,7 +739,7 @@ def generate_tactical_report(
return TacticalReportResponse(error_message=message)

conversation = conversation_plugin.instance.get_conversation(
conversation_id=incident.conversation.channel_id, important_reaction=important_reaction
conversation_id=incident.conversation.channel_id, include_user_details=True, important_reaction=important_reaction
)
if not conversation:
message = f"Tactical report not generated for {incident.name}. No conversation found."
Expand Down
5 changes: 4 additions & 1 deletion src/dispatch/plugins/dispatch_slack/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,14 +450,16 @@ def fetch_events(
raise

def get_conversation(
self, conversation_id: str, oldest: str = "0", important_reaction: str | None = None
self, conversation_id: str, oldest: str = "0", include_user_details = False, important_reaction: str | None = None
) -> list:
"""
Fetches the top-level posts from a Slack conversation.

Args:
conversation_id (str): The ID of the Slack conversation.
oldest (str): The oldest timestamp to fetch messages from.
include_user_details (bool): Whether to resolve user name and email information.
important_reaction (str): Emoji reaction indicating important messages.

Returns:
list: A list of tuples containing the timestamp and user ID of each message.
Expand All @@ -468,6 +470,7 @@ def get_conversation(
conversation_id,
oldest,
include_message_text=True,
include_user_details=include_user_details,
important_reaction=important_reaction,
)

Expand Down
45 changes: 42 additions & 3 deletions src/dispatch/plugins/dispatch_slack/service.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import functools
import heapq
import logging
import re
from datetime import datetime

from blockkit.surfaces import Block
Expand Down Expand Up @@ -610,16 +611,39 @@ def get_channel_activity(
conversation_id: str,
oldest: str = "0",
include_message_text: bool = False,
include_user_details: bool = False,
important_reaction: str | None = None,
) -> list:
"""Gets all top-level messages for a given Slack channel.

Args:
client (WebClient): Slack client responsible for API calls
conversation_id (str): Channel ID to reference
oldest (int): Oldest timestamp to fetch messages from
include_message_text (bool): Include message text (in addition to datetime and user id)
include_user_details (bool): Include user name and email information
important_reaction (str): Optional emoji reaction designating important messages

Returns:
A sorted list of tuples (utc_dt, user_id) of each message in the channel,
or (utc_dt, user_id, message_text), depending on include_message_text.
"""
result = []
cursor = None

def mention_resolver(user_match):
"""
Helper function to extract user informations from @ mentions in messages.
"""
user_id = user_match.group(1)
try:
user_info = get_user_info_by_id(client, user_id)
return user_info.get('real_name', f"{user_id} (name not found)")
except SlackApiError as e:
log.warning(f"Error resolving mentioned Slack user: {e}")
# fall back on id
return user_id

while True:
response = make_call(
client,
Expand All @@ -640,13 +664,28 @@ def get_channel_activity(
if "user" in message:
user_id = resolve_user(client, message["user"])["id"]
utc_dt = datetime.utcfromtimestamp(float(message["ts"]))

message_result = [utc_dt, user_id]

if include_message_text:
message_text = message.get("text", "")
if has_important_reaction(message, important_reaction):
message_text = f"IMPORTANT!: {message_text}"
heapq.heappush(result, (utc_dt, user_id, message_text))
else:
heapq.heappush(result, (utc_dt, user_id))

if include_user_details: # attempt to resolve mentioned users
message_text = re.sub(r'<@(\w+)>', mention_resolver, message_text)

message_result.append(message_text)

if include_user_details:
user_details = get_user_info_by_id(client, user_id)
user_name = user_details.get('real_name', "Name not found")
user_profile = user_details.get('profile', {})
user_display_name = user_profile.get('display_name_normalized', "DisplayName not found")
user_email = user_profile.get('email', "Email not found")
message_result.extend([user_name, user_display_name, user_email])

heapq.heappush(result, tuple(message_result))

if not response["has_more"]:
break
Expand Down
Loading