@@ -2932,8 +2932,35 @@ async def notify_user_message_added(
29322932 role : str ,
29332933):
29342934 """Notify user when a new message is added to any conversation."""
2935- # Truncate message for notification (keep first 100 chars)
2936- preview = message [:100 ] + "..." if len (message ) > 100 else message
2935+ # Build clean notification preview: resolve mentions, strip metadata
2936+ import re
2937+ from DB import get_session , User
2938+
2939+ preview = message
2940+ try :
2941+ with get_session () as session :
2942+ # Resolve <@userId> mentions
2943+ mention_re = re .compile (r"<@([0-9a-f-]{36})>" )
2944+ uids = set (mention_re .findall (preview ))
2945+ if uids :
2946+ uid_to_name = {}
2947+ users = session .query (User ).filter (User .id .in_ (list (uids ))).all ()
2948+ for u in users :
2949+ first = getattr (u , "first_name" , "" ) or ""
2950+ last = getattr (u , "last_name" , "" ) or ""
2951+ uid_to_name [str (u .id )] = f"{ first } { last } " .strip () or "User"
2952+ preview = mention_re .sub (
2953+ lambda m : f"@{ uid_to_name .get (m .group (1 ), 'User' )} " , preview
2954+ )
2955+ # Strip metadata tags and markdown bold
2956+ preview = re .sub (r"\[ref:[^\]]+\]" , "" , preview )
2957+ preview = re .sub (r"\[uid:[^\]]+\]" , "" , preview )
2958+ preview = preview .replace ("**" , "" )
2959+ preview = re .sub (r"\s+" , " " , preview ).strip ()
2960+ except Exception :
2961+ pass
2962+ if len (preview ) > 100 :
2963+ preview = preview [:100 ] + "..."
29372964 await user_notification_manager .broadcast_to_user (
29382965 user_id ,
29392966 {
@@ -2966,12 +2993,57 @@ async def notify_conversation_participants_message_added(
29662993 from DB import get_session , ConversationParticipant , User , Conversation
29672994 import re
29682995
2969- preview = message [:100 ] + "..." if len (message ) > 100 else message
2996+ # Build a clean preview: resolve <@userId> mentions, strip metadata tags
2997+ def clean_notification_preview (raw : str , session ) -> str :
2998+ """Clean raw message text for notification previews."""
2999+ text = raw
3000+ # Strip reply blockquote lines (> **Author** said: ... > quoted)
3001+ if text .startswith ("> **" ):
3002+ lines = text .split ("\n " )
3003+ i = 0
3004+ if re .match (r"^> \*\*.+\*\* said:" , lines [0 ]):
3005+ i = 1
3006+ while i < len (lines ) and (lines [i ].startswith ("> " ) or lines [i ] == ">" ):
3007+ i += 1
3008+ # Skip blank separator
3009+ if i < len (lines ) and lines [i ].strip () == "" :
3010+ i += 1
3011+ actual = "\n " .join (lines [i :]).strip ()
3012+ if actual :
3013+ text = actual
3014+ # Resolve <@userId> to display names
3015+ mention_re = re .compile (r"<@([0-9a-f-]{36})>" )
3016+ uids_in_text = set (mention_re .findall (text ))
3017+ if uids_in_text :
3018+ uid_to_name = {}
3019+ users = (
3020+ session .query (User ).filter (User .id .in_ (list (uids_in_text ))).all ()
3021+ )
3022+ for u in users :
3023+ first = getattr (u , "first_name" , "" ) or ""
3024+ last = getattr (u , "last_name" , "" ) or ""
3025+ uid_to_name [str (u .id )] = f"{ first } { last } " .strip () or "User"
3026+ text = mention_re .sub (
3027+ lambda m : f"@{ uid_to_name .get (m .group (1 ), 'User' )} " , text
3028+ )
3029+ # Strip [ref:...] and [uid:...] metadata tags
3030+ text = re .sub (r"\[ref:[^\]]+\]" , "" , text )
3031+ text = re .sub (r"\[uid:[^\]]+\]" , "" , text )
3032+ # Strip markdown bold from remaining text
3033+ text = text .replace ("**" , "" )
3034+ # Collapse whitespace
3035+ text = re .sub (r"\s+" , " " , text ).strip ()
3036+ # Truncate
3037+ if len (text ) > 100 :
3038+ text = text [:100 ] + "..."
3039+ return text
29703040
29713041 # Look up sender display name and conversation's company_id
29723042 sender_name = "Someone"
29733043 company_id = None
29743044 with get_session () as session :
3045+ preview = clean_notification_preview (message , session )
3046+
29753047 sender = session .query (User ).filter (User .id == sender_user_id ).first ()
29763048 if sender :
29773049 first = getattr (sender , "first_name" , "" ) or ""
0 commit comments