fix: keep resumed CLI sessions in sidebar cap
This commit is contained in:
@@ -3,6 +3,9 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Keep capped CLI/agent sidebar scans ordered by latest message activity as well as session start time, so long-lived CLI sessions that were resumed recently stay visible in the sidebar window.
|
||||
|
||||
## [v0.51.100] — 2026-05-20 — Release BX (stage-393 — 3-PR deep-review batch — lazy journal recovery retry + faster profile-switch + cross-tab session list SSE sync)
|
||||
|
||||
|
||||
@@ -433,10 +433,13 @@ def read_importable_agent_session_rows(
|
||||
if result_limit == 0:
|
||||
return []
|
||||
# The sidebar only needs a small visible window. Bound the expensive
|
||||
# messages join to a recent-session candidate set instead of
|
||||
# messages join to a recent-activity candidate set instead of
|
||||
# aggregating every historical Hermes state.db session before
|
||||
# slicing in Python. Oversampling preserves room for hidden
|
||||
# compression segments or other rows filtered after projection.
|
||||
# slicing in Python. The candidate ordering must include the latest
|
||||
# message timestamp, not only ``started_at``: long-lived CLI sessions
|
||||
# can be resumed days later and should still surface at the top.
|
||||
# Oversampling preserves room for hidden compression segments or
|
||||
# other rows filtered after projection.
|
||||
candidate_limit = max(result_limit * 8, result_limit)
|
||||
cur.execute(
|
||||
f"""
|
||||
@@ -444,7 +447,11 @@ def read_importable_agent_session_rows(
|
||||
SELECT s.id
|
||||
FROM sessions s
|
||||
WHERE {' AND '.join(where_clauses)}
|
||||
ORDER BY s.started_at DESC
|
||||
ORDER BY COALESCE(
|
||||
(SELECT MAX(mx.timestamp) FROM messages mx WHERE mx.session_id = s.id),
|
||||
s.started_at
|
||||
) DESC,
|
||||
s.started_at DESC
|
||||
LIMIT ?
|
||||
)
|
||||
{select_sql}
|
||||
|
||||
@@ -71,9 +71,43 @@ def test_importable_agent_rows_push_sidebar_limit_into_sql(tmp_path):
|
||||
src = (REPO_ROOT / "api" / "agent_sessions.py").read_text()
|
||||
assert "WITH candidates AS" in src
|
||||
assert "JOIN candidates c ON c.id = s.id" in src
|
||||
assert "SELECT MAX(mx.timestamp) FROM messages mx WHERE mx.session_id = s.id" in src
|
||||
assert "candidate_limit = max(result_limit * 8, result_limit)" in src
|
||||
|
||||
|
||||
def test_importable_agent_rows_limit_includes_resumed_old_session(tmp_path):
|
||||
"""The capped candidate window must not hide old sessions resumed recently."""
|
||||
db = tmp_path / "state.db"
|
||||
_make_state_db(db, sessions=200, messages_per_session=1)
|
||||
|
||||
old_started = time.time() - 60 * 60 * 24 * 30
|
||||
recent_activity = time.time() + 60
|
||||
conn = sqlite3.connect(str(db))
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO sessions
|
||||
(id, source, session_source, title, model, started_at, message_count, parent_session_id, ended_at, end_reason)
|
||||
VALUES ('cli_resumed_old', 'cli', 'cli', 'Old resumed session', 'openai/gpt-5', ?, 2, NULL, NULL, NULL)
|
||||
""",
|
||||
(old_started,),
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO messages (id, session_id, role, content, timestamp) VALUES ('old_msg_1', 'cli_resumed_old', 'user', 'old hello', ?)",
|
||||
(old_started,),
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO messages (id, session_id, role, content, timestamp) VALUES ('old_msg_2', 'cli_resumed_old', 'assistant', 'recent reply', ?)",
|
||||
(recent_activity,),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
rows = agent_sessions.read_importable_agent_session_rows(db, limit=20, exclude_sources=("webui",))
|
||||
|
||||
assert rows[0]["id"] == "cli_resumed_old"
|
||||
assert rows[0]["actual_message_count"] == 2
|
||||
|
||||
|
||||
def test_importable_agent_rows_zero_limit_skips_query_work(tmp_path):
|
||||
db = tmp_path / "state.db"
|
||||
_make_state_db(db, sessions=5, messages_per_session=1)
|
||||
|
||||
Reference in New Issue
Block a user