From 57abe691733c6d5c09c548e26b350fe527af7f2b Mon Sep 17 00:00:00 2001 From: lekt8 Date: Wed, 3 Jun 2026 03:20:48 +0800 Subject: [PATCH] Let the output "x" delete work when no model/session exists (#1431) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deleteMessage() bailed at `if (!sessionId) return;`, so the "x" on an output shown before a model/API was selected did nothing — there's no session yet (issue #1428). The session id is only needed for the server-side delete; without one (or with no persisted message ids) we now fall through to removing the DOM, so the "x" always at least dismisses the bubble. Co-authored-by: Claude Opus 4.8 (1M context) --- static/js/chat.js | 11 +++++--- tests/test_delete_message_no_session.py | 34 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 tests/test_delete_message_no_session.py diff --git a/static/js/chat.js b/static/js/chat.js index 10f7e05..6e75dab 100644 --- a/static/js/chat.js +++ b/static/js/chat.js @@ -4037,8 +4037,11 @@ import createResearchSynapse from './researchSynapse.js'; const clickedIndex = allMsgs.indexOf(msgElement); if (clickedIndex < 0) return; + // No early-out on a missing session: an output shown before any model was + // selected (issue #1428) has no session/persisted rows, but its "x" must + // still remove it. We only need the session id for the server-side delete + // below; without one we fall back to removing the DOM. const sessionId = sessionModule.getCurrentSessionId(); - if (!sessionId) return; const clickedIsUser = msgElement.classList.contains('msg-user'); @@ -4114,8 +4117,10 @@ import createResearchSynapse from './researchSynapse.js'; } } - if (!msgIds.length) { - // Fallback: just remove DOM elements if no DB IDs available + if (!msgIds.length || !sessionId) { + // No persisted rows to delete (no DB IDs, or no session at all — e.g. an + // error output shown before a model was selected, #1428). Just remove the + // DOM so the "x" works regardless. domToRemove.forEach(el => el.remove()); if (uiModule) uiModule.showToast('Message deleted'); return; diff --git a/tests/test_delete_message_no_session.py b/tests/test_delete_message_no_session.py new file mode 100644 index 0000000..1ce1cf1 --- /dev/null +++ b/tests/test_delete_message_no_session.py @@ -0,0 +1,34 @@ +"""Regression guard for issue #1428 — the "x" on a chat output did nothing when +no model/API was selected. + +deleteMessage() bailed at `if (!sessionId) return;`. An output shown before a +model is picked has no session and no persisted rows, so the early-out meant the +"x" never even removed the bubble from the DOM. The delete now falls through to +DOM removal when there's no session / no DB ids. + +chat.js pulls in browser globals so it can't run under node; guard at the source. +""" +import re +from pathlib import Path + +SRC = Path(__file__).resolve().parent.parent / "static/js/chat.js" + + +def _delete_message_body() -> str: + text = SRC.read_text(encoding="utf-8") + start = text.index("export async function deleteMessage(") + rest = text[start:] + m = re.search(r"\n export (async )?function ", rest[1:]) + return rest[: m.start() + 1] if m else rest + + +def test_delete_does_not_early_return_on_missing_session(): + body = _delete_message_body() + # The bug was an unconditional early-out when no session existed. + assert not re.search(r"if\s*\(\s*!sessionId\s*\)\s*return\s*;", body), ( + "deleteMessage must not early-return on a missing session (#1428)" + ) + # The DOM-removal fallback must also fire when there's no session. + assert re.search(r"!msgIds\.length\s*\|\|\s*!sessionId", body), ( + "DOM-removal fallback should cover the no-session case" + )