From b9e8ade4b665ecf9f125b3068ab680ed79121232 Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Sun, 5 Jul 2026 01:16:19 +0000 Subject: [PATCH] fix(#5587): keep active CLI sessions visible before final output Self-built stage of contributor PR; gate-pass. Co-authored-by: rodboev --- api/agent_sessions.py | 11 ++++++- tests/test_gateway_sync.py | 60 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/api/agent_sessions.py b/api/agent_sessions.py index e1555270..17511c18 100644 --- a/api/agent_sessions.py +++ b/api/agent_sessions.py @@ -214,10 +214,19 @@ def is_cli_session_row_visible(row: dict) -> bool: if not is_cli_session_row(row): return True - message_count = _as_positive_int(row.get("actual_message_count") or row.get("message_count")) + actual_message_count = _as_positive_int(row.get("actual_message_count")) + message_count = actual_message_count or _as_positive_int(row.get("message_count")) if message_count <= 0: return False + if ( + actual_message_count > 0 + and _count_user_turns(row) > 0 + and row.get("ended_at") is None + and not row.get("end_reason") + ): + return True + if "tui" in { _normalize_source_name(row.get("source")), _normalize_source_name(row.get("source_tag")), diff --git a/tests/test_gateway_sync.py b/tests/test_gateway_sync.py index 6aeb3425..9af91012 100644 --- a/tests/test_gateway_sync.py +++ b/tests/test_gateway_sync.py @@ -293,6 +293,66 @@ def test_webui_state_db_session_without_sidecar_appears_when_agent_sessions_enab post('/api/settings', {'show_cli_sessions': False}) +def test_active_cli_state_db_session_with_persisted_user_turn_is_visible_in_cli_bucket(): + """Active default-title CLI rows with persisted user content stay visible in the CLI bucket.""" + conn = _ensure_state_db() + active_sid = 'cli_active_visible_001' + older_sid = 'cli_older_visible_001' + ended_sid = 'cli_ended_hidden_001' + now = time.time() + try: + conn.execute( + "INSERT OR REPLACE INTO sessions " + "(id, source, title, model, started_at, message_count, ended_at, end_reason) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + (active_sid, 'cli', 'Untitled', 'openai/gpt-5', now + 20, 0, None, None), + ) + conn.execute("DELETE FROM messages WHERE session_id = ?", (active_sid,)) + _insert_message(conn, active_sid, 'user', 'Active CLI session still running', now + 21) + + conn.execute( + "INSERT OR REPLACE INTO sessions " + "(id, source, title, model, started_at, message_count, ended_at, end_reason) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + (older_sid, 'cli', 'Named CLI Session', 'openai/gpt-5', now, 1, None, None), + ) + conn.execute("DELETE FROM messages WHERE session_id = ?", (older_sid,)) + _insert_message(conn, older_sid, 'user', 'Older visible CLI session', now + 1) + + conn.execute( + "INSERT OR REPLACE INTO sessions " + "(id, source, title, model, started_at, message_count, ended_at, end_reason) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + (ended_sid, 'cli', 'Untitled', 'openai/gpt-5', now + 10, 1, now + 11, 'cli-close'), + ) + conn.execute("DELETE FROM messages WHERE session_id = ?", (ended_sid,)) + _insert_message(conn, ended_sid, 'user', 'Ended CLI session', now + 11) + conn.commit() + + post('/api/settings', {'show_cli_sessions': True}) + + data, status = get('/api/sessions?sidebar_source=cli') + assert status == 200 + sessions = data.get('sessions', []) + session_ids = [s.get('session_id') for s in sessions] + assert active_sid in session_ids + assert older_sid in session_ids + assert ended_sid not in session_ids, "ended default-title CLI rows with one user turn stay hidden" + + active = next(s for s in sessions if s.get('session_id') == active_sid) + older = next(s for s in sessions if s.get('session_id') == older_sid) + assert active.get('message_count') == 1 + assert active.get('updated_at') > older.get('updated_at') + assert session_ids.index(active_sid) < session_ids.index(older_sid) + finally: + try: + _remove_test_sessions(conn, active_sid, older_sid, ended_sid) + conn.close() + except Exception: + pass + post('/api/settings', {'show_cli_sessions': False}) + + def test_gateway_sessions_without_messages_are_hidden_from_sidebar(): """Regression: empty agent session rows must not appear as broken sidebar entries.""" conn = _ensure_state_db()