From 370fd9210e97aafe42b7afadf44109a0789fcd3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Can=20=C3=9Cnal?= Date: Mon, 1 Jun 2026 19:54:58 +0300 Subject: [PATCH] feat(settings): make non-webui sidebar session cap configurable --- CHANGELOG.md | 3 + api/config.py | 2 + api/models.py | 17 ++++- api/routes.py | 18 +++++- static/boot.js | 2 + static/index.html | 5 ++ static/panels.js | 10 +++ tests/test_configurable_cli_session_limit.py | 66 ++++++++++++++++++++ 8 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 tests/test_configurable_cli_session_limit.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 77c6a2a251..ba2f1396e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## [Unreleased] +### Added +- Settings now includes a configurable **Non-WebUI session limit** (`cli_session_limit`) for sidebar rows imported from CLI/gateway sources. The cap is persisted via `/api/settings`, applied to the state.db import path (`api/models.py`) and the final sidebar visibility cap (`api/routes.py`), while preserving the legacy fallback of 20 when the setting is missing or invalid. + ## [v0.51.195] — 2026-06-01 — Release FO (stage-batch7 — hide attachment path markers in chat UI) ### Fixed diff --git a/api/config.py b/api/config.py index c0ca41fe30..2fc76645ce 100644 --- a/api/config.py +++ b/api/config.py @@ -4804,6 +4804,7 @@ def _get_session_agent_lock(session_id: str) -> threading.Lock: "show_tps": False, # show tokens-per-second chip in assistant message headers "fade_text_effect": False, # animate newly streamed words with a lightweight fade-in effect "show_cli_sessions": False, # merge CLI sessions from state.db into the sidebar + "cli_session_limit": 20, # max non-WebUI sessions to keep visible in sidebar when enabled "show_previous_messaging_sessions": False, # show older Telegram/Discord/etc. reset segments "sync_to_insights": False, # mirror WebUI token usage to state.db for /insights "check_for_updates": True, # check if webui/agent repos are behind upstream @@ -4949,6 +4950,7 @@ def load_settings() -> dict: "busy_input_mode": {"queue", "interrupt", "steer"}, } _SETTINGS_INT_RANGES = { + "cli_session_limit": (1, 500), "pinned_sessions_limit": (1, 99), "inflight_state_max_sessions": (1, 25), "inflight_state_max_messages": (1, 100), diff --git a/api/models.py b/api/models.py index 8bfb8c587f..35d2bcf803 100644 --- a/api/models.py +++ b/api/models.py @@ -3300,6 +3300,21 @@ def _cli_sessions_cache_ttl_seconds() -> float: return 5.0 +def _cli_visible_session_limit() -> int: + """Resolve non-WebUI sidebar session cap from settings. + + Keeps legacy behavior (20) when the setting is missing/invalid. + """ + try: + raw = _cfg.load_settings().get('cli_session_limit', CLI_VISIBLE_SESSION_LIMIT) + value = int(raw) + except Exception: + value = CLI_VISIBLE_SESSION_LIMIT + if value < 1: + return CLI_VISIBLE_SESSION_LIMIT + return value + + def _path_cache_key(path) -> str | None: if path is None: return None @@ -3384,7 +3399,7 @@ def _cron_pid(): for row in read_importable_agent_session_rows( db_path, - limit=CLI_VISIBLE_SESSION_LIMIT, + limit=_cli_visible_session_limit(), log=logger, exclude_sources=None, ): diff --git a/api/routes.py b/api/routes.py index 9a604ddc2f..d44c300189 100644 --- a/api/routes.py +++ b/api/routes.py @@ -2662,6 +2662,19 @@ def _dedupe_cli_sidebar_sessions_for_api(cli: list[dict], represented_webui_ids: CLI_VISIBLE_SESSION_CAP = 20 +def _resolve_cli_session_cap(settings: dict | None = None) -> int: + """Resolve non-WebUI sidebar cap from settings with safe fallback.""" + try: + source = settings if isinstance(settings, dict) else load_settings() + raw = source.get("cli_session_limit", CLI_VISIBLE_SESSION_CAP) + value = int(raw) + except Exception: + value = CLI_VISIBLE_SESSION_CAP + if value < 1: + return CLI_VISIBLE_SESSION_CAP + return value + + def _cap_recent_cli_sessions(sessions: list[dict], cli_cap: int = CLI_VISIBLE_SESSION_CAP) -> list[dict]: """Keep only the most recent CLI-visible sessions after filtering.""" if cli_cap <= 0: @@ -4887,7 +4900,10 @@ def handle_get(handler, parsed) -> bool: ) if show_cli_sessions: diag.stage("cli_cap") - scoped = _cap_recent_cli_sessions(scoped, cli_cap=CLI_VISIBLE_SESSION_CAP) + scoped = _cap_recent_cli_sessions( + scoped, + cli_cap=_resolve_cli_session_cap(settings), + ) diag.stage("redact_sessions") safe_merged = [] for s in scoped: diff --git a/static/boot.js b/static/boot.js index 034dc82c6c..6e2ef70b41 100644 --- a/static/boot.js +++ b/static/boot.js @@ -1621,6 +1621,7 @@ function applyBotName(){ window._showTps=!!s.show_tps; window._fadeTextEffect=!!s.fade_text_effect; window._showCliSessions=!!s.show_cli_sessions; + window._cliSessionLimit=parseInt(s.cli_session_limit||20,10)||20; window._showPreviousMessagingSessions=!!s.show_previous_messaging_sessions; window._soundEnabled=!!s.sound_enabled; window._notificationsEnabled=!!s.notifications_enabled; @@ -1721,6 +1722,7 @@ function applyBotName(){ window._showTps=false; window._fadeTextEffect=false; window._showCliSessions=false; + window._cliSessionLimit=20; window._soundEnabled=false; window._notificationsEnabled=false; window._whatsNewSummaryEnabled=false; diff --git a/static/index.html b/static/index.html index 32efe8583e..bee934db11 100644 --- a/static/index.html +++ b/static/index.html @@ -1178,6 +1178,11 @@

What can I help with?

Show conversations from CLI, Telegram, Discord, Slack, and other channels in the session list. Click to import and continue.
+
+ + +
Maximum number of non-WebUI sessions (CLI/Telegram/Discord/etc.) shown in the sidebar when enabled. Default is 20.
+