From ec704356ac4f5612e1db1a6ac44745f16fd0b47a Mon Sep 17 00:00:00 2001 From: AJV20 <24819659+AJV20@users.noreply.github.com> Date: Sun, 31 May 2026 20:52:33 -0400 Subject: [PATCH 1/2] fix: hide attachment path markers in chat UI --- api/models.py | 6 +++- static/sessions.js | 6 +++- static/ui.js | 6 +++- tests/test_chat_upload_attachment_paths.py | 34 ++++++++++++++++++++++ tests/test_workspace_display_prefix.py | 2 +- 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/api/models.py b/api/models.py index 9b6bddc9..8bfb8c58 100644 --- a/api/models.py +++ b/api/models.py @@ -2858,6 +2858,10 @@ def all_sessions(diag=None): return result +def _strip_attached_files_marker(text: str) -> str: + return re.sub(r"\n\n\[Attached files: [^\]]+\]$", "", str(text or "")).strip() + + def title_from(messages, fallback: str='Untitled'): """Derive a session title from the first user message.""" for m in messages: @@ -2865,7 +2869,7 @@ def title_from(messages, fallback: str='Untitled'): c = m.get('content', '') if isinstance(c, list): c = ' '.join(p.get('text', '') for p in c if isinstance(p, dict) and p.get('type') == 'text') - text = str(c).strip() + text = _strip_attached_files_marker(str(c)) if text: return text[:64] return fallback diff --git a/static/sessions.js b/static/sessions.js index e0d8d646..ddde4a12 100644 --- a/static/sessions.js +++ b/static/sessions.js @@ -3508,7 +3508,11 @@ function _collapseSessionLineageForSidebar(sessions){ } function _sessionDisplayTitle(s){ - const title=String((s&&(s.display_title||s._state_db_title||s.title))||'Untitled').trim(); + const rawTitle=String((s&&(s.display_title||s._state_db_title||s.title))||'Untitled').trim(); + const strip=(typeof _stripAttachedFilesMarker==='function') + ? _stripAttachedFilesMarker + : (text)=>String(text||'').replace(/\n\n\[Attached files: [^\]]+\]$/,'').trim(); + const title=strip(rawTitle); return title||'Untitled'; } diff --git a/static/ui.js b/static/ui.js index e0b576bc..44f13bb5 100644 --- a/static/ui.js +++ b/static/ui.js @@ -3564,6 +3564,10 @@ function renderMd(raw){ return s; } +function _stripAttachedFilesMarkerForDisplay(text){ + return String(text||'').replace(/\n\n\[Attached files: [^\]]+\]$/,'').trim(); +} + function setStatus(t){ if(!t)return; showToast(t, 4000); @@ -6530,7 +6534,7 @@ function renderMessages(options){ if(!isUser&&_isMarkerOnlyAssistantCompressionMessage(m)){ content='**Error:** No response received after context compression. Please retry.'; } - const displayContent=isUser?_stripWorkspaceDisplayPrefix(content):content; + const displayContent=isUser?_stripAttachedFilesMarkerForDisplay(_stripWorkspaceDisplayPrefix(content)):content; if(thinkingText&&!isUser){ thinkingText=_stripVisibleAssistantEchoFromThinking(thinkingText, displayContent); } diff --git a/tests/test_chat_upload_attachment_paths.py b/tests/test_chat_upload_attachment_paths.py index 08f7f2cc..4a4b1955 100644 --- a/tests/test_chat_upload_attachment_paths.py +++ b/tests/test_chat_upload_attachment_paths.py @@ -22,6 +22,40 @@ def test_image_uploads_use_server_path_in_attached_files_context(): assert "uploadedPaths=uploaded.map(u=>u&&u.path?u.path" in src +def test_attached_files_context_is_hidden_from_user_message_display(): + """Persist full attachment paths for the agent without showing them in chat.""" + ui_src = (ROOT / "static" / "ui.js").read_text(encoding="utf-8") + + assert "function _stripAttachedFilesMarkerForDisplay" in ui_src + assert "_stripAttachedFilesMarkerForDisplay(_stripWorkspaceDisplayPrefix(content))" in ui_src + assert "dataset.rawText=String(displayContent).trim()" in ui_src + + +def test_attached_files_context_is_hidden_from_sidebar_titles(): + """Sidebar rows should not expose absolute uploaded image paths in titles.""" + sessions_src = (ROOT / "static" / "sessions.js").read_text(encoding="utf-8") + + assert "function _stripAttachedFilesMarker" in sessions_src + assert "? _stripAttachedFilesMarker" in sessions_src + assert "replace(/\\n\\n\\[Attached files: [^\\]]+\\]$/" in sessions_src + + +def test_server_provisional_titles_strip_attached_files_context(): + """Server-generated provisional titles must not include the path suffix.""" + from api.models import title_from + + title = title_from([ + { + "role": "user", + "content": "why is llm wiki not working?\n\n[Attached files: /tmp/private/Screenshot.png]", + } + ]) + + assert title == "why is llm wiki not working?" + assert "Attached files" not in title + assert "/tmp/private" not in title + + def test_duplicate_upload_response_reports_actual_stored_filename(tmp_path, monkeypatch): """Duplicate upload names should report the suffixed stored basename.""" monkeypatch.setenv("HERMES_WEBUI_ATTACHMENT_DIR", str(tmp_path)) diff --git a/tests/test_workspace_display_prefix.py b/tests/test_workspace_display_prefix.py index d95014f1..f2356a71 100644 --- a/tests/test_workspace_display_prefix.py +++ b/tests/test_workspace_display_prefix.py @@ -35,7 +35,7 @@ def test_user_render_uses_stripped_display_content_without_preempting_context_ca assert loop_end != -1, "assistant render branch not found after user branch" render_prefix = src[loop_start:loop_end] - display_idx = render_prefix.find("const displayContent=isUser?_stripWorkspaceDisplayPrefix(content):content;") + display_idx = render_prefix.find("const displayContent=isUser?_stripAttachedFilesMarkerForDisplay(_stripWorkspaceDisplayPrefix(content)):content;") context_idx = render_prefix.find("if(_isContextCompactionMessage(m))") user_idx = render_prefix.find("if(isUser)") assert display_idx != -1, "display content stripper not used in render loop" From c1a3c3ef28c58c93712938cf866cd865618727ab Mon Sep 17 00:00:00 2001 From: nesquena-hermes <[email protected]> Date: Mon, 1 Jun 2026 05:32:33 +0000 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20v0.51.195=20release=20header=20(sta?= =?UTF-8?q?ge-batch7=20=E2=80=94=20#3296=20hide=20attachment=20path=20mark?= =?UTF-8?q?ers)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69f463e2..77c6a2a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ ## [Unreleased] +## [v0.51.195] — 2026-06-01 — Release FO (stage-batch7 — hide attachment path markers in chat UI) + +### Fixed +- Uploaded image attachment path context (`[Attached files: …]`) remains available to the agent in the stored message, but the chat transcript, sidebar display title, and server-derived provisional titles no longer show the raw path suffix to the user (#3296, @AJV20). + ## [v0.51.194] — 2026-06-01 — Release FN (stage-batch6 — profiles config-import-cycle fix) ### Fixed