mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
fix(slack): surface thread images/files as markers in fetched thread context
Images and files posted in a Slack thread before the bot joins were invisible to the agent: _fetch_thread_context renders text only, and a caption-less image post was dropped from context entirely (empty text → skip). "@bot what do you think of the chart above?" read as a question about nothing. _render_message_text now appends a compact, sanitized marker per file attachment — [image: chart.png], [video: demo.mp4], [audio: note.m4a], [file: report.pdf (application/pdf)] — so the agent can SEE that prior thread messages carried attachments and ask for a re-share when it needs the bytes. Filenames are stripped of newlines/brackets so a hostile name can't fake context structure. Because both thread-context formatting and parent-text rendering go through _render_message_text, markers appear on the cold-start hydrate, the explicit-mention delta refresh, restart rehydration, and reply_to_text. Reapplied from #32315 onto the current adapter (original patched the pre-plugin gateway/platforms/slack.py, moved in the plugin migration; annotation labels reworked to per-file typed markers, download side handled separately).
This commit is contained in:
parent
3ec5a06f4f
commit
26a2fda8d7
1 changed files with 33 additions and 0 deletions
|
|
@ -101,6 +101,26 @@ _SLACK_SPECIAL_MENTION_RE = re.compile(
|
|||
r"<!(?:everyone|channel|here)(?:\|[^>\n]*)?>", re.IGNORECASE
|
||||
)
|
||||
|
||||
|
||||
def _slack_file_marker(file_obj: Dict[str, Any]) -> str:
|
||||
"""Render a compact text marker for a Slack file attachment.
|
||||
|
||||
Used by :meth:`SlackAdapter._render_message_text` so thread-context and
|
||||
parent-text rendering surface that a message carried images/files even
|
||||
though the context fetch is text-only. Name is sanitized (newlines and
|
||||
brackets stripped) so a hostile filename can't fake context structure.
|
||||
"""
|
||||
name = str(file_obj.get("name") or file_obj.get("title") or file_obj.get("id") or "file")
|
||||
name = re.sub(r"[\r\n\[\]]+", " ", name).strip() or "file"
|
||||
mimetype = str(file_obj.get("mimetype") or "")
|
||||
if mimetype.startswith("image/"):
|
||||
return f"[image: {name}]"
|
||||
if mimetype.startswith("video/"):
|
||||
return f"[video: {name}]"
|
||||
if mimetype.startswith("audio/"):
|
||||
return f"[audio: {name}]"
|
||||
return f"[file: {name} ({mimetype})]" if mimetype else f"[file: {name}]"
|
||||
|
||||
# ContextVar carrying the user_id of the slash-command invoker.
|
||||
# Set in _handle_slash_command, read in send() to match the correct
|
||||
# stashed response_url when multiple users issue commands on the same
|
||||
|
|
@ -6131,6 +6151,19 @@ class SlackAdapter(BasePlatformAdapter):
|
|||
new_urls = [u for u in urls if u not in msg_text and all(u not in e for e in extras)]
|
||||
if new_urls:
|
||||
extras.append("URLs: " + ", ".join(new_urls))
|
||||
# Surface file/image attachments as compact text markers. The
|
||||
# thread-context fetch is text-only, so without this the agent has
|
||||
# no idea prior messages carried images/files at all (#69185,
|
||||
# #32315): "@bot what do you think of the chart above?" reads as a
|
||||
# question about nothing. Markers keep context bounded — the agent
|
||||
# can ask for a re-share when it needs the actual bytes.
|
||||
files = msg.get("files")
|
||||
if isinstance(files, list):
|
||||
markers = [
|
||||
_slack_file_marker(f) for f in files if isinstance(f, dict)
|
||||
]
|
||||
if markers:
|
||||
extras.append(" ".join(markers))
|
||||
if extras:
|
||||
addendum = "\n".join(extras)
|
||||
msg_text = (msg_text + "\n" + addendum).strip() if msg_text else addendum
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue