Skip to content

Commit d5e852e

Browse files
committed
Merge branch 'pull_request_conversation_1' into pull_request_conversation_2
2 parents fe432d2 + 5864f99 commit d5e852e

File tree

10 files changed

+371
-966
lines changed

10 files changed

+371
-966
lines changed

packages/slackBotFunction/app/slack/slack_events.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
from app.services.slack import get_friendly_channel_name, post_error_message
2828
from app.utils.handler_utils import (
2929
conversation_key_and_root,
30-
extract_conversation_context,
3130
extract_pull_request_id,
3231
forward_event_to_pull_request_lambda,
3332
is_duplicate_event,
@@ -119,7 +118,6 @@ def _handle_session_management(
119118
user_id: str,
120119
channel: str,
121120
thread_ts: str,
122-
context_type: str,
123121
message_ts: str,
124122
) -> None:
125123
"""Handle Bedrock session creation and cleanup"""
@@ -131,7 +129,7 @@ def _handle_session_management(
131129
kb_response["sessionId"],
132130
user_id,
133131
channel,
134-
thread_ts if context_type == constants.CONTEXT_TYPE_THREAD else None,
132+
thread_ts,
135133
message_ts,
136134
)
137135
elif session_id:
@@ -206,7 +204,7 @@ def process_feedback_event(
206204
client.chat_postMessage(**params)
207205
except Exception as e:
208206
logger.error(f"Failed to post channel feedback ack: {e}", extra={"error": traceback.format_exc()})
209-
_, _, thread_ts = extract_conversation_context(event)
207+
_, thread_ts = conversation_key_and_root(event)
210208
post_error_message(channel=channel_id, thread_ts=thread_ts, client=client)
211209

212210

@@ -267,7 +265,7 @@ def process_async_slack_action(body: Dict[str, Any], client: WebClient) -> None:
267265
def process_async_slack_event(event: Dict[str, Any], event_id: str, client: WebClient) -> None:
268266
original_message_text = (event.get("text") or "").strip()
269267
message_text = strip_mentions(message_text=original_message_text)
270-
conversation_key, _, thread_ts = extract_conversation_context(event)
268+
conversation_key, thread_ts = conversation_key_and_root(event)
271269
user_id = event.get("user", "unknown")
272270
channel_id = event["channel"]
273271
conversation_key, thread_root = conversation_key_and_root(event=event)
@@ -305,13 +303,13 @@ def process_slack_message(event: Dict[str, Any], event_id: str, client: WebClien
305303
try:
306304
user_id = event["user"]
307305
channel = event["channel"]
308-
conversation_key, context_type, thread_ts = extract_conversation_context(event)
306+
conversation_key, thread_ts = conversation_key_and_root(event)
309307

310308
# Remove Slack user mentions from message text
311309
user_query = re.sub(r"<@[UW][A-Z0-9]+(\|[^>]+)?>", "", event["text"]).strip()
312310

313311
logger.info(
314-
f"Processing {context_type} message from user {user_id}",
312+
f"Processing message from user {user_id}",
315313
extra={"user_query": user_query, "conversation_key": conversation_key, "event_id": event_id},
316314
)
317315

@@ -342,15 +340,14 @@ def process_slack_message(event: Dict[str, Any], event_id: str, client: WebClien
342340
message_ts = post["ts"]
343341

344342
_handle_session_management(
345-
conversation_key,
346-
session_data,
347-
session_id,
348-
kb_response,
349-
user_id,
350-
channel,
351-
thread_ts,
352-
context_type,
353-
message_ts,
343+
conversation_key=conversation_key,
344+
session_data=session_data,
345+
session_id=session_id,
346+
kb_response=kb_response,
347+
user_id=user_id,
348+
channel=channel,
349+
thread_ts=thread_ts,
350+
message_ts=message_ts,
354351
)
355352

356353
# Store Q&A pair for feedback correlation

packages/slackBotFunction/app/slack/slack_handlers.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@
1111
from functools import lru_cache
1212
import traceback
1313
from typing import Any, Dict
14-
from slack_bolt import Ack, App, BoltRequest
14+
from slack_bolt import Ack, App
1515
from slack_sdk import WebClient
1616
from app.core.config import (
1717
get_logger,
1818
)
1919
from app.utils.handler_utils import (
2020
conversation_key_and_root,
21-
extract_conversation_context,
2221
extract_session_pull_request_id,
2322
forward_action_to_pull_request_lambda,
2423
forward_event_to_pull_request_lambda,
@@ -86,7 +85,7 @@ def feedback_handler(body: Dict[str, Any], client: WebClient) -> None:
8685
# ================================================================
8786

8887

89-
def unified_message_handler(client: WebClient, event: Dict[str, Any], req: BoltRequest, body: Dict[str, Any]) -> None:
88+
def unified_message_handler(client: WebClient, event: Dict[str, Any], body: Dict[str, Any]) -> None:
9089
"""
9190
All messages get processed by this code
9291
If message starts with FEEDBACK_PREFIX then handle feedback message and return
@@ -99,7 +98,6 @@ def unified_message_handler(client: WebClient, event: Dict[str, Any], req: BoltR
9998
return
10099
user_id = event.get("user", "unknown")
101100
conversation_key, _ = conversation_key_and_root(event=event)
102-
conversation_key, _, _ = extract_conversation_context(event)
103101
session_pull_request_id = extract_session_pull_request_id(conversation_key)
104102
if session_pull_request_id:
105103
logger.info(

packages/slackBotFunction/app/utils/handler_utils.py

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,52 +53,60 @@ def respond_with_eyes(event: Dict[str, Any], client: WebClient) -> None:
5353
logger.warning("Failed to respond with eyes", extra={"error": traceback.format_exc()})
5454

5555

56-
def forward_event_to_pull_request_lambda(
57-
pull_request_id: str, event: Dict[str, Any], event_id: str, store_pull_request_id: bool
58-
) -> None:
56+
def get_pull_request_lambda_arn(pull_request_id: str) -> str:
5957
cloudformation_client: CloudFormationClient = boto3.client("cloudformation")
60-
lambda_client: LambdaClient = boto3.client("lambda")
6158
try:
6259
logger.debug("Getting arn for pull request", extra={"pull_request_id": pull_request_id})
6360
response = cloudformation_client.describe_stacks(StackName=f"epsam-pr-{pull_request_id}")
6461
outputs = {o["OutputKey"]: o["OutputValue"] for o in response["Stacks"][0]["Outputs"]}
65-
6662
pull_request_lambda_arn = outputs.get("SlackBotLambdaArn")
67-
logger.debug("Triggering pull request lambda", extra={"lambda_arn": pull_request_lambda_arn})
63+
return pull_request_lambda_arn
64+
except Exception as e:
65+
logger.error("Failed to get pull request lambda arn", extra={"error": traceback.format_exc()})
66+
raise e
67+
68+
69+
def forward_event_to_pull_request_lambda(
70+
pull_request_id: str, event: Dict[str, Any], event_id: str, store_pull_request_id: bool
71+
) -> None:
72+
lambda_client: LambdaClient = boto3.client("lambda")
73+
try:
74+
pull_request_lambda_arn = get_pull_request_lambda_arn(pull_request_id=pull_request_id)
75+
# strip pull request prefix and id from message text
6876
message_text = event["text"]
6977
_, extracted_message = extract_pull_request_id(message_text)
7078
event["text"] = extracted_message
79+
7180
lambda_payload = {"pull_request_event": True, "slack_event": {"event": event, "event_id": event_id}}
72-
response = lambda_client.invoke(
81+
logger.debug(
82+
"Forwarding event to pull request lambda",
83+
extra={"lambda_arn": pull_request_lambda_arn, "lambda_payload": lambda_payload},
84+
)
85+
lambda_client.invoke(
7386
FunctionName=pull_request_lambda_arn, InvocationType="Event", Payload=json.dumps(lambda_payload)
7487
)
7588
logger.info("Triggered pull request lambda", extra={"lambda_arn": pull_request_lambda_arn})
7689

7790
if store_pull_request_id:
78-
conversation_key, _, _ = extract_conversation_context(event)
91+
conversation_key, _ = conversation_key_and_root(event)
7992
item = {"pk": conversation_key, "sk": constants.PULL_REQUEST_SK, "pull_request_id": pull_request_id}
93+
store_state_information(item=item)
8094

81-
store_state_information(item=item)
8295
except Exception as e:
8396
logger.error("Failed to trigger pull request lambda", extra={"error": traceback.format_exc()})
8497
raise e
8598

8699

87100
def forward_action_to_pull_request_lambda(body: Dict[str, Any], pull_request_id: str) -> None:
88-
cloudformation_client: CloudFormationClient = boto3.client("cloudformation")
89101
lambda_client: LambdaClient = boto3.client("lambda")
90102
try:
91-
logger.debug("Getting arn for pull request", extra={"pull_request_id": pull_request_id})
92-
response = cloudformation_client.describe_stacks(StackName=f"epsam-pr-{pull_request_id}")
93-
outputs = {o["OutputKey"]: o["OutputValue"] for o in response["Stacks"][0]["Outputs"]}
94-
95-
pull_request_lambda_arn = outputs.get("SlackBotLambdaArn")
103+
pull_request_lambda_arn = get_pull_request_lambda_arn(pull_request_id=pull_request_id)
96104
lambda_payload = {"pull_request_action": True, "slack_body": body}
97105
logger.debug(
98106
"Forwarding action to pull request lambda",
99107
extra={"lambda_arn": pull_request_lambda_arn, "lambda_payload": lambda_payload},
100108
)
101-
response = lambda_client.invoke(
109+
lambda_client.invoke(
102110
FunctionName=pull_request_lambda_arn, InvocationType="Event", Payload=json.dumps(lambda_payload)
103111
)
104112
logger.info("Triggered pull request lambda", extra={"lambda_arn": pull_request_lambda_arn})
@@ -152,12 +160,13 @@ def strip_mentions(message_text: str) -> str:
152160
return re.sub(r"<@[UW][A-Z0-9]+(\|[^>]+)?>", "", message_text or "").strip()
153161

154162

155-
def extract_pull_request_id(text: str) -> Tuple[str, str]:
163+
def extract_pull_request_id(text: str) -> Tuple[str | None, str]:
156164
# Regex: PULL_REQUEST_PREFIX + optional space + number + space + rest of text
157165
pattern = re.escape(constants.PULL_REQUEST_PREFIX) + r"\s*(\d+)\s+(.+)"
158166
match = re.match(pattern, text)
159167
if not match:
160-
raise ValueError("Text does not match expected format (#pr <number> <text>)")
168+
logger.warning("Can not extract pull request id from text", extra={"text": text})
169+
return None, text
161170
pr_number = int(match.group(1))
162171
rest_text = match.group(2)
163172
return pr_number, rest_text
@@ -181,18 +190,6 @@ def conversation_key_and_root(event: Dict[str, Any]) -> Tuple[str, str]:
181190
return f"{constants.THREAD_PREFIX}{channel_id}#{root}", root
182191

183192

184-
def extract_conversation_context(event: Dict[str, Any]) -> Tuple[str, str, str | None]:
185-
"""Extract conversation key and thread context from event"""
186-
channel = event["channel"]
187-
# Determine conversation context: DM vs channel thread
188-
if event.get("channel_type") == constants.CHANNEL_TYPE_IM:
189-
thread_root = event.get("thread_ts", event["ts"])
190-
return f"{constants.DM_PREFIX}{channel}#{thread_root}", constants.CONTEXT_TYPE_THREAD, thread_root
191-
else:
192-
thread_root = event.get("thread_ts", event["ts"])
193-
return f"{constants.THREAD_PREFIX}{channel}#{thread_root}", constants.CONTEXT_TYPE_THREAD, thread_root
194-
195-
196193
def extract_session_pull_request_id(conversation_key: str) -> str | None:
197194
"""Check if the conversation is associated with a pull request"""
198195
logger.debug("Checking for existing pull request session", extra={"conversation_key": conversation_key})

0 commit comments

Comments
 (0)