diff --git a/gateway/platforms/base.py b/gateway/platforms/base.py index 34ebc385fa91..5899843aa1ee 100644 --- a/gateway/platforms/base.py +++ b/gateway/platforms/base.py @@ -2137,7 +2137,7 @@ def extract_media(content: str) -> Tuple[List[Tuple[str, bool]], str]: # Extract MEDIA: tags, allowing optional whitespace after the colon # and quoted/backticked paths for LLM-formatted outputs. media_pattern = re.compile( - r'''[`"']?MEDIA:\s*(?P`[^`\n]+`|"[^"\n]+"|'[^'\n]+'|(?:~/|/)\S+(?:[^\S\n]+\S+)*?\.(?:png|jpe?g|gif|webp|mp4|mov|avi|mkv|webm|ogg|opus|mp3|wav|m4a|flac|epub|pdf|zip|rar|7z|docx?|xlsx?|pptx?|txt|csv|apk|ipa)(?=[\s`"',;:)\]}]|$)|\S+)[`"']?''' + r'''[`"']?MEDIA:\s*(?P`[^`\n]+`|"[^"\n]+"|'[^'\n]+'|(?:~/|/)\S+(?:[^\S\n]+\S+)*?\.(?:png|jpe?g|gif|webp|mp4|mov|avi|mkv|webm|ogg|opus|mp3|wav|m4a|flac|epub|pdf|zip|rar|7z|docx?|xlsx?|pptx?|txt|csv|apk|ipa)(?=[\s`"',;:)\]}]|$))[`"']?''' ) for match in media_pattern.finditer(content): path = match.group("path").strip() diff --git a/gateway/platforms/mattermost.py b/gateway/platforms/mattermost.py index 9487f8a1edfc..574f465b1dd5 100644 --- a/gateway/platforms/mattermost.py +++ b/gateway/platforms/mattermost.py @@ -471,9 +471,10 @@ async def _send_local_file( p = Path(file_path) if not p.exists(): - return await self.send( - chat_id, f"{caption or ''}\n(file not found: {file_path})", reply_to + logger.warning( + "Mattermost: local file not found, skipping: %s", file_path ) + return SendResult(success=True, message_id=None) fname = file_name or p.name ct = mimetypes.guess_type(fname)[0] or "application/octet-stream" diff --git a/gateway/run.py b/gateway/run.py index de4bf9fe7fd0..84617387c140 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -15774,7 +15774,14 @@ def _clarify_callback_sync(question: str, choices) -> str: if _hm.get("role") in {"tool", "function"}: _hc = _hm.get("content", "") if "MEDIA:" in _hc: - for _match in re.finditer(r'MEDIA:(\S+)', _hc): + _TOOL_MEDIA_RE = re.compile( + r'MEDIA:((?:/|~\/)\S+\.(?:png|jpe?g|gif|webp|' + r'mp4|mov|avi|mkv|webm|ogg|opus|mp3|wav|m4a|' + r'flac|epub|pdf|zip|rar|7z|docx?|xlsx?|pptx?|' + r'txt|csv|apk|ipa))', + re.IGNORECASE + ) + for _match in _TOOL_MEDIA_RE.finditer(_hc): _p = _match.group(1).strip().rstrip('",}') if _p: _history_media_paths.add(_p) @@ -16063,7 +16070,14 @@ def _approval_notify_sync(approval_data: dict) -> None: if msg.get("role") in {"tool", "function"}: content = msg.get("content", "") if "MEDIA:" in content: - for match in re.finditer(r'MEDIA:(\S+)', content): + _TOOL_MEDIA_RE = re.compile( + r'MEDIA:((?:/|~\/)\S+\.(?:png|jpe?g|gif|webp|' + r'mp4|mov|avi|mkv|webm|ogg|opus|mp3|wav|m4a|' + r'flac|epub|pdf|zip|rar|7z|docx?|xlsx?|pptx?|' + r'txt|csv|apk|ipa))', + re.IGNORECASE + ) + for match in _TOOL_MEDIA_RE.finditer(content): path = match.group(1).strip().rstrip('",}') if path and path not in _history_media_paths: media_tags.append(f"MEDIA:{path}")