fix: exclude hidden snapshots from pin quota

This commit is contained in:
ai-ag2026
2026-05-30 11:45:24 +02:00
parent 7dc4273a21
commit 09d2f4be2f
6 changed files with 70 additions and 4 deletions
+22 -2
View File
@@ -99,6 +99,25 @@ def _session_field(session, field, default=None):
return getattr(session, field, default)
def _session_counts_toward_pin_quota(session) -> bool:
"""Return True when a pinned session should consume visible pin quota."""
if not _session_field(session, "pinned", False):
return False
if _session_field(session, "archived", False):
return False
if isinstance(session, dict):
row = session
elif hasattr(session, "compact"):
row = session.compact()
else:
row = {
"pre_compression_snapshot": _session_field(session, "pre_compression_snapshot", False),
"source_tag": _session_field(session, "source_tag", None),
"default_hidden": _session_field(session, "default_hidden", False),
}
return not _hide_from_default_sidebar(row)
# ── Profile-scoped session/project filtering (#1611, #1614) ────────────────
#
# Sessions and projects are stored in the WebUI sidecar without per-row
@@ -2730,6 +2749,7 @@ from api.models import (
merge_session_messages_append_only,
_session_message_merge_key,
_is_empty_partial_activity_message,
_hide_from_default_sidebar,
prune_session_from_index,
ensure_cron_project,
is_cron_session,
@@ -6509,7 +6529,7 @@ def handle_post(handler, parsed) -> bool:
# so must run outside our own LOCK acquire below).
persisted_pinned_ids = {
_session_field(existing, "session_id", None) for existing in all_sessions()
if _session_field(existing, "pinned", False) and not _session_field(existing, "archived", False)
if _session_counts_toward_pin_quota(existing)
}
with LOCK:
# Final authoritative count: merge persisted-pinned with the
@@ -6519,7 +6539,7 @@ def handle_post(handler, parsed) -> bool:
pinned_ids = set(persisted_pinned_ids)
pinned_ids.update(
sid for sid, existing in SESSIONS.items()
if getattr(existing, "pinned", False) and not getattr(existing, "archived", False)
if _session_counts_toward_pin_quota(existing)
)
pinned_ids.discard(body["session_id"])
pinned_sessions_limit = int(load_settings().get("pinned_sessions_limit", 3) or 3)
+4
View File
@@ -2286,8 +2286,10 @@ def _preserve_pre_compression_snapshot(s, old_sid: str) -> None:
# pre-existing parent_session_id lineage.
saved_sid = s.session_id
saved_snapshot = bool(getattr(s, 'pre_compression_snapshot', False))
saved_pinned = bool(getattr(s, 'pinned', False))
s.session_id = old_sid
s.pre_compression_snapshot = True
s.pinned = False
# Stage-359 / PR #2295: clear runtime stream-state fields on the
# archived snapshot so the sidebar does not reopen the parent as
# a permanently-running session while the child already holds the
@@ -2314,6 +2316,7 @@ def _preserve_pre_compression_snapshot(s, old_sid: str) -> None:
finally:
s.session_id = saved_sid
s.pre_compression_snapshot = saved_snapshot
s.pinned = saved_pinned
s.active_stream_id = saved_active_stream_id
s.pending_user_message = saved_pending_user_message
s.pending_attachments = saved_pending_attachments
@@ -2326,6 +2329,7 @@ def _preserve_pre_compression_snapshot(s, old_sid: str) -> None:
snapshot = Session.load(old_sid)
if snapshot:
snapshot.pre_compression_snapshot = True
snapshot.pinned = False
# Stage-359 Opus SHOULD-FIX: clear runtime fields on the loaded
# snapshot too. If the disk snapshot was last persisted while the
# parent was live, it could carry a stale active_stream_id /