Release v0.51.302 — Release JR (stage-brick — mobile/iOS brick + large-session perf hotfixes) (#3754)
Some checks failed
Release & Docker / release (push) Has been cancelled

* fix(ui): stop hidden toast from intercepting clicks on mobile (#3735)

The .toast container kept pointer-events:auto while hidden (opacity:0), so its
fixed padding sat over mobile profile action buttons and ate their clicks. Set
pointer-events:none when hidden; restore auto on .toast.show.

Co-authored-by: timlawrenz <timlawrenz@users.noreply.github.com>

* fix(sessions): rename saves on blur so iOS Safari rename works (#3729)

iOS Safari has no Enter key; the keyboard 'Done' button fires blur, and the old
onblur=cancel discarded the rename. Flip blur to save (Escape still cancels) for
session rename and project create/rename, with a _finishDone guard to prevent a
double-fire between blur and the API callback.

Co-authored-by: reinocheong <reinocheong@users.noreply.github.com>

* perf(session): skip fuzzy dedup matching for giant merge payloads (#3730)

Large tool/log payloads made _matching_visible_duplicate() casefold+regex-tokenize
multi-megabyte contents on every visible key, so /api/session took 10s+ and blocked
/api/sessions for ~19s. Keep loose normalization lazy+cached and skip substring/fuzzy
matching for non-exact payloads >200KB; exact visible-key matches still short-circuit.

Co-authored-by: alvistar <alvistar@users.noreply.github.com>

* docs(changelog): stamp v0.51.302 — Release JR (stage-brick brick/perf hotfixes #3735 #3729 #3730)

---------

Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: timlawrenz <timlawrenz@users.noreply.github.com>
Co-authored-by: reinocheong <reinocheong@users.noreply.github.com>
Co-authored-by: alvistar <alvistar@users.noreply.github.com>
This commit is contained in:
nesquena-hermes
2026-06-06 16:58:13 -07:00
committed by GitHub
parent 1649a22f5a
commit bf088cbbc4
6 changed files with 99 additions and 12 deletions

View File

@@ -4040,7 +4040,6 @@ def _session_message_visible_key(msg: dict):
def _build_visible_duplicate_lookup(visible_keys: set[tuple]) -> dict:
by_role = {}
loose_by_key = {}
for key in visible_keys:
try:
role = key[0]
@@ -4050,8 +4049,10 @@ def _build_visible_duplicate_lookup(visible_keys: set[tuple]) -> dict:
if not content:
continue
by_role.setdefault(role, []).append(key)
loose_by_key[key] = _loose_session_message_content(content)
return {"keys": visible_keys, "by_role": by_role, "loose_by_key": loose_by_key}
# Keep loose_by_key lazy. Some transcripts contain multi-megabyte tool
# outputs; eagerly casefolding + regex-tokenizing every visible key on every
# duplicate probe made /api/session take 10s+ and blocked /api/sessions.
return {"keys": visible_keys, "by_role": by_role, "loose_by_key": {}}
def _matching_visible_duplicate(visible_key: tuple, visible_keys: set[tuple], lookup: dict | None = None):
@@ -4064,16 +4065,28 @@ def _matching_visible_duplicate(visible_key: tuple, visible_keys: set[tuple], lo
if lookup is None:
lookup = _build_visible_duplicate_lookup(visible_keys)
loose_content = None
loose_by_key = lookup.setdefault("loose_by_key", {})
for existing_key in lookup.get("by_role", {}).get(role, []):
existing_role = existing_key[0]
existing_content = existing_key[1] if len(existing_key) > 1 else ""
if role != existing_role or not existing_content:
continue
# Exact visible-key equality was checked above. For very large payloads
# (tool logs / request dumps), Python-in substring and fuzzy-token
# comparisons are both expensive and low-value; doing them repeatedly
# made session loading block the whole WebUI for many seconds. Keep
# fuzzy matching for normal chat-sized text, but do exact-only matching
# for giant payloads.
if max(len(content), len(existing_content)) > 200_000:
continue
if content in existing_content or existing_content in content:
return existing_key
if loose_content is None:
loose_content = _loose_session_message_content(content)
loose_existing = lookup.get("loose_by_key", {}).get(existing_key, "")
loose_existing = loose_by_key.get(existing_key)
if loose_existing is None:
loose_existing = _loose_session_message_content(existing_content)
loose_by_key[existing_key] = loose_existing
if loose_content and loose_existing and (
loose_content in loose_existing or loose_existing in loose_content
):