@@ -68,6 +68,7 @@ def _build_delivery_text(
6868 priority : str ,
6969 reply_required : bool ,
7070 event_id : str ,
71+ refs : list [dict [str , Any ]],
7172 attachments : list [dict [str , Any ]],
7273 src_group_id : str = "" ,
7374 src_event_id : str = "" ,
@@ -82,6 +83,9 @@ def _build_delivery_text(
8283 prefix_lines .append (f"[cccc] RELAYED FROM (group_id={ src_group_id } , event_id={ src_event_id } ):" )
8384 if prefix_lines :
8485 delivery_text = "\n " .join (prefix_lines ) + "\n " + delivery_text
86+ ref_lines = _render_delivery_refs (refs )
87+ if ref_lines :
88+ delivery_text = (delivery_text .rstrip ("\n " ) + "\n \n " + "\n " .join (ref_lines )).strip ()
8589 if attachments :
8690 lines = ["[cccc] Attachments:" ]
8791 for attachment in attachments [:8 ]:
@@ -95,6 +99,112 @@ def _build_delivery_text(
9599 return delivery_text
96100
97101
102+ def _compact_delivery_text (value : Any , * , limit : int ) -> str :
103+ text = re .sub (r"\s+" , " " , str (value or "" ).strip ())
104+ if not text :
105+ return ""
106+ if len (text ) <= limit :
107+ return text
108+ return text [: max (1 , limit - 1 )].rstrip () + "…"
109+
110+
111+ def _presentation_slot_label (slot_id : str , label : str ) -> str :
112+ if label :
113+ return label
114+ match = re .search (r"(\d+)$" , slot_id )
115+ if match :
116+ try :
117+ return f"P{ int (match .group (1 ))} "
118+ except Exception :
119+ pass
120+ return slot_id or "Presentation"
121+
122+
123+ def _render_delivery_refs (refs : list [dict [str , Any ]]) -> list [str ]:
124+ if not refs :
125+ return []
126+
127+ lines = ["[cccc] References:" ]
128+ rendered = 0
129+
130+ for ref in refs :
131+ if not isinstance (ref , dict ):
132+ continue
133+ kind = str (ref .get ("kind" ) or "" ).strip ()
134+ if kind == "presentation_ref" :
135+ slot_id = _compact_delivery_text (ref .get ("slot_id" ), limit = 32 )
136+ label = _presentation_slot_label (
137+ slot_id ,
138+ _compact_delivery_text (ref .get ("label" ), limit = 24 ),
139+ )
140+ locator_label = _compact_delivery_text (ref .get ("locator_label" ), limit = 48 )
141+ title = _compact_delivery_text (ref .get ("title" ), limit = 72 )
142+ header = f"- { label } "
143+ if slot_id :
144+ header += f" ({ slot_id } )"
145+ if locator_label :
146+ header += f" · { locator_label } "
147+ if title :
148+ header += f" — { title } "
149+ lines .append (header )
150+ excerpt = _compact_delivery_text (ref .get ("excerpt" ), limit = 120 )
151+ if excerpt :
152+ lines .append (f' excerpt: "{ excerpt } "' )
153+ href = _compact_delivery_text (ref .get ("href" ), limit = 120 )
154+ if href :
155+ lines .append (f" href: { href } " )
156+ locator = ref .get ("locator" ) if isinstance (ref .get ("locator" ), dict ) else {}
157+ locator_url = _compact_delivery_text (locator .get ("url" ), limit = 120 )
158+ if locator_url and locator_url != href :
159+ lines .append (f" view_url: { locator_url } " )
160+ captured_at = _compact_delivery_text (locator .get ("captured_at" ), limit = 48 )
161+ if captured_at :
162+ lines .append (f" captured_at: { captured_at } " )
163+ viewer_scroll_top = locator .get ("viewer_scroll_top" )
164+ if isinstance (viewer_scroll_top , (int , float )) or str (viewer_scroll_top or "" ).strip ():
165+ try :
166+ scroll_value = int (float (viewer_scroll_top ))
167+ except Exception :
168+ scroll_value = None
169+ if scroll_value is not None and scroll_value >= 0 :
170+ lines .append (f" scroll_top: { scroll_value } " )
171+ snapshot = ref .get ("snapshot" ) if isinstance (ref .get ("snapshot" ), dict ) else {}
172+ snapshot_path = _compact_delivery_text (snapshot .get ("path" ), limit = 120 )
173+ if snapshot_path :
174+ width = snapshot .get ("width" )
175+ height = snapshot .get ("height" )
176+ size_label = ""
177+ try :
178+ width_value = int (width )
179+ height_value = int (height )
180+ if width_value > 0 and height_value > 0 :
181+ size_label = f" ({ width_value } x{ height_value } )"
182+ except Exception :
183+ size_label = ""
184+ lines .append (f" snapshot: { snapshot_path } { size_label } " )
185+ rendered += 1
186+ if rendered >= 4 :
187+ break
188+ continue
189+
190+ summary = _compact_delivery_text (
191+ ref .get ("title" ) or ref .get ("path" ) or ref .get ("url" ) or kind ,
192+ limit = 96 ,
193+ )
194+ if summary :
195+ prefix = kind or "ref"
196+ lines .append (f"- { prefix } : { summary } " )
197+ rendered += 1
198+ if rendered >= 4 :
199+ break
200+
201+ if rendered == 0 :
202+ return []
203+ if len (refs ) > rendered :
204+ lines .append (f"- … ({ len (refs ) - rendered } more)" )
205+ return lines
206+
207+
98208def _touch_registry_updated_at (group_id : str , ts : str ) -> None :
99209 try :
100210 reg = load_registry ()
@@ -106,6 +216,16 @@ def _touch_registry_updated_at(group_id: str, ts: str) -> None:
106216 pass
107217
108218
219+ def _normalize_refs (raw : Any ) -> list [dict [str , Any ]]:
220+ if not isinstance (raw , list ):
221+ return []
222+ refs : list [dict [str , Any ]] = []
223+ for item in raw :
224+ if isinstance (item , dict ):
225+ refs .append (item )
226+ return refs
227+
228+
109229def _notify_headless_targets (
110230 * ,
111231 group : Any ,
@@ -269,6 +389,7 @@ def handle_send(
269389 attachments = normalize_attachments (group , args .get ("attachments" ))
270390 except Exception as e :
271391 return _error ("invalid_attachments" , str (e ))
392+ refs = _normalize_refs (args .get ("refs" ))
272393
273394 if not text .strip () and not attachments :
274395 return _error ("empty_message" , "message text cannot be empty" )
@@ -285,6 +406,7 @@ def handle_send(
285406 priority = priority ,
286407 reply_required = reply_required ,
287408 to = to ,
409+ refs = refs ,
288410 attachments = attachments ,
289411 source_platform = source_platform or None ,
290412 source_user_name = source_user_name or None ,
@@ -307,6 +429,7 @@ def handle_send(
307429 priority = priority ,
308430 reply_required = reply_required ,
309431 event_id = event_id ,
432+ refs = refs ,
310433 attachments = attachments ,
311434 src_group_id = src_group_id ,
312435 src_event_id = src_event_id ,
@@ -447,6 +570,7 @@ def handle_reply(
447570 attachments = normalize_attachments (group , args .get ("attachments" ))
448571 except Exception as e :
449572 return _error ("invalid_attachments" , str (e ))
573+ refs = _normalize_refs (args .get ("refs" ))
450574 if not text .strip () and not attachments :
451575 return _error ("empty_message" , "message text cannot be empty" )
452576
@@ -464,6 +588,7 @@ def handle_reply(
464588 to = to ,
465589 reply_to = reply_to ,
466590 quote_text = quote_text ,
591+ refs = refs ,
467592 attachments = attachments ,
468593 source_platform = original_source_platform or None ,
469594 source_user_name = original_source_user_name or None ,
@@ -508,6 +633,7 @@ def handle_reply(
508633 priority = priority ,
509634 reply_required = reply_required ,
510635 event_id = event_id ,
636+ refs = refs ,
511637 attachments = attachments ,
512638 )
513639 for actor in list_actors (group ):
0 commit comments