diff --git a/CHANGELOG.md b/CHANGELOG.md index a990d204..9fce67ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## [Unreleased] +### Fixed + +- Duplicate chat uploads now report the actual stored filename in `/api/upload` responses, so suffixed files such as `photo-1.png` do not appear under the original basename in WebUI attachment metadata. + ## [v0.51.152] — 2026-05-28 — Release DX (stage-batch34 — single-PR optional gateway-backed browser chat) ### Added diff --git a/api/upload.py b/api/upload.py index dc0aa0c1..b36cde46 100644 --- a/api/upload.py +++ b/api/upload.py @@ -125,7 +125,7 @@ def handle_upload(handler): dest.write_bytes(file_bytes) mime = mimetypes.guess_type(safe_name)[0] or 'application/octet-stream' return j(handler, { - 'filename': safe_name, + 'filename': dest.name, 'path': str(dest), 'size': dest.stat().st_size, 'mime': mime, diff --git a/tests/test_chat_upload_attachment_paths.py b/tests/test_chat_upload_attachment_paths.py index 6e0fba38..08f7f2cc 100644 --- a/tests/test_chat_upload_attachment_paths.py +++ b/tests/test_chat_upload_attachment_paths.py @@ -4,6 +4,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parents[1] MESSAGES_JS = ROOT / "static" / "messages.js" +UPLOAD_PY = ROOT / "api" / "upload.py" def test_image_uploads_use_server_path_in_attached_files_context(): @@ -19,3 +20,23 @@ def test_image_uploads_use_server_path_in_attached_files_context(): assert "uploadedPaths=uploaded.map(u=>u&&u.is_image?" not in src assert "uploadedPaths=uploaded.map(u=>u&&u.path?u.path" in src + + +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)) + + from api.upload import _sanitize_upload_name, _upload_destination + + safe_name = _sanitize_upload_name("photo.png") + first = _upload_destination("session-a", safe_name) + first.write_bytes(b"first") + second = _upload_destination("session-a", safe_name) + + assert first.name == "photo.png" + assert second.name == "photo-1.png" + + src = UPLOAD_PY.read_text(encoding="utf-8") + handle_body = src[src.index("def handle_upload"):src.index("def extract_archive", src.index("def handle_upload"))] + assert "'filename': dest.name" in handle_body + assert "'filename': safe_name" not in handle_body