2626from utils .session_manager import SessionManager
2727from utils .langfuse_client import FeedbackClient
2828from utils .scoring import submit_feedback_score
29+ from utils .config_models import get_escalation_config
2930
3031app = App (token = os .environ .get ("SLACK_INTEGRATION_BOT_TOKEN" , os .environ .get ("SLACK_BOT_TOKEN" , "" )))
3132APP_NAME = os .environ .get ("SLACK_INTEGRATION_APP_NAME" , os .environ .get ("APP_NAME" , "CAIPE" ))
@@ -147,7 +148,13 @@ def handle_mention(event, say, client):
147148 session_manager .clear_skipped (thread_ts )
148149
149150 if is_humble_followup :
150- mention_prompt = config .defaults .humble_followup_prompt
151+ # Use per-channel followup prompt from overthink config, fall back to global default
152+ followup = (
153+ channel_config .qanda .overthink .followup_prompt
154+ or channel_config .ai_alerts .overthink .followup_prompt
155+ or config .defaults .humble_followup_prompt
156+ )
157+ mention_prompt = followup
151158 elif channel_config .custom_prompt :
152159 mention_prompt = channel_config .custom_prompt
153160 else :
@@ -164,6 +171,9 @@ def handle_mention(event, say, client):
164171
165172 team_id = event .get ("team" )
166173
174+ default_config = channel_config .default if channel_config .default else {}
175+ esc_config = get_escalation_config (default_config )
176+
167177 result = ai .stream_a2a_response (
168178 a2a_client = a2a_client ,
169179 slack_client = client ,
@@ -175,6 +185,7 @@ def handle_mention(event, say, client):
175185 context_id = context_id ,
176186 metadata = request_metadata if request_metadata else None ,
177187 session_manager = session_manager ,
188+ escalation_config = esc_config ,
178189 )
179190
180191 if isinstance (result , dict ) and result .get ("retry_needed" ):
@@ -261,6 +272,8 @@ def handle_qanda_message(event, say, client):
261272 final_message = f"The user email is { user_email } \n \n { final_message } "
262273 request_metadata ["user_email" ] = user_email
263274
275+ esc_config = get_escalation_config (default_config )
276+
264277 result = ai .stream_a2a_response (
265278 a2a_client = a2a_client ,
266279 slack_client = client ,
@@ -272,7 +285,8 @@ def handle_qanda_message(event, say, client):
272285 context_id = context_id ,
273286 metadata = request_metadata ,
274287 session_manager = session_manager ,
275- overthink_mode = channel_config .qanda .overthink ,
288+ overthink_config = channel_config .qanda .overthink if channel_config .qanda .overthink .enabled else None ,
289+ escalation_config = esc_config ,
276290 )
277291
278292 if isinstance (result , dict ) and result .get ("skipped" ):
@@ -481,7 +495,8 @@ def handle_message_events(body, say, client):
481495 if not default_config or not isinstance (default_config , dict ):
482496 raise ValueError (f"Channel { channel_id } is missing required 'default' config" )
483497
484- ai .handle_ai_alert_processing (
498+ alerts_overthink = channel_config .ai_alerts .overthink
499+ result = ai .handle_ai_alert_processing (
485500 a2a_client ,
486501 client ,
487502 event ,
@@ -490,8 +505,15 @@ def handle_message_events(body, say, client):
490505 default_config ,
491506 session_manager ,
492507 custom_prompt = channel_config .ai_alerts .custom_prompt ,
508+ overthink_config = alerts_overthink if alerts_overthink .enabled else None ,
493509 )
494510
511+ if isinstance (result , dict ) and result .get ("skipped" ):
512+ reason = result .get ("reason" , "unknown" )
513+ alert_ts = event .get ("ts" , "unknown" )
514+ logger .info (f"[{ alert_ts } ] Overthink: skipped alert processing ({ reason } )" )
515+ session_manager .set_skipped (alert_ts , True )
516+
495517
496518# =============================================================================
497519# HITL (Human-in-the-Loop) Form Action Handler
@@ -678,6 +700,84 @@ def handle_caipe_retry(ack, body, client):
678700 logger .exception (f"Error handling retry: { e } " )
679701
680702
703+ # =============================================================================
704+ # Escalation Action Handlers
705+ # =============================================================================
706+ @app .action ("caipe_escalation_get_help" )
707+ def handle_escalation_get_help (ack , body , client ):
708+ ack ()
709+ try :
710+ from utils .escalation import execute_escalation
711+
712+ user_id = body .get ("user" , {}).get ("id" )
713+ action = body .get ("actions" , [{}])[0 ]
714+ parts = action .get ("value" , "" ).split ("|" )
715+ channel_id = parts [0 ] if len (parts ) > 0 else None
716+ thread_ts = parts [1 ] if len (parts ) > 1 else None
717+ if not channel_id or not thread_ts :
718+ return
719+
720+ # Track escalation in feedback
721+ submit_feedback_score (
722+ thread_ts = thread_ts , user_id = user_id , channel_id = channel_id ,
723+ feedback_value = "escalation_requested" , slack_client = client ,
724+ session_manager = session_manager , config = config ,
725+ feedback_client = feedback_client ,
726+ )
727+
728+ client .chat_postEphemeral (
729+ channel = channel_id , user = user_id , thread_ts = thread_ts ,
730+ text = "Got it! Connecting you with a human..." ,
731+ )
732+
733+ # Get escalation config for this channel
734+ channel_config = config .channels .get (channel_id )
735+ if not channel_config :
736+ return
737+ esc_config = get_escalation_config (channel_config .default or {})
738+ if not esc_config :
739+ return
740+
741+ # Determine the parent message ts (root of thread)
742+ message = body .get ("message" , {})
743+ parent_ts = message .get ("thread_ts" ) or thread_ts
744+
745+ execute_escalation (
746+ slack_client = client , a2a_client = a2a_client ,
747+ channel_id = channel_id , thread_ts = thread_ts ,
748+ parent_ts = parent_ts , user_id = user_id ,
749+ escalation_config = esc_config ,
750+ )
751+ except Exception as e :
752+ logger .exception (f"Error handling escalation: { e } " )
753+
754+
755+ @app .action ("caipe_delete_message" )
756+ def handle_delete_message (ack , body , client ):
757+ ack ()
758+ try :
759+ user_id = body .get ("user" , {}).get ("id" )
760+ channel_id = body .get ("channel" , {}).get ("id" )
761+ message = body .get ("message" , {})
762+ message_ts = message .get ("ts" )
763+ thread_ts = message .get ("thread_ts" ) or message_ts
764+
765+ if not channel_id or not message_ts :
766+ return
767+
768+ submit_feedback_score (
769+ thread_ts = thread_ts , user_id = user_id , channel_id = channel_id ,
770+ feedback_value = "message_deleted" , slack_client = client ,
771+ session_manager = session_manager , config = config ,
772+ feedback_client = feedback_client ,
773+ )
774+
775+ client .chat_delete (channel = channel_id , ts = message_ts )
776+ logger .info (f"[{ thread_ts } ] Message { message_ts } deleted by <@{ user_id } >" )
777+ except Exception as e :
778+ logger .exception (f"Error handling message delete: { e } " )
779+
780+
681781def _open_feedback_modal (ack , body , client , feedback_type ):
682782 ack ()
683783 try :
0 commit comments