Merge PR #7798 from webtecnica/fix/7548-cli-archived-sessions-projection

This commit is contained in:
nesquena-hermes committed 2026-09-24 06:57:17 +00:00
commit 18cf0fa0ba
5 files changed
+137 -7

No files matched your search

+3 -1
View File
@@ -576,7 +576,7 @@ def _project_agent_session_rows(rows: list[dict]) -> list[dict]:
# expects from "Show agent sessions" sorted by activity.
for key in (
'id', 'model', 'message_count', 'actual_message_count', 'actual_user_message_count',
'ended_at', 'end_reason', 'last_activity',
'ended_at', 'end_reason', 'last_activity', 'archived',
):
if key in tip:
merged[key] = tip[key]
@@ -683,6 +683,7 @@ def read_importable_agent_session_rows(
origin_chat_id_expr = _optional_col('origin_chat_id', session_cols)
origin_user_id_expr = _optional_col('origin_user_id', session_cols)
platform_expr = _optional_col('platform', session_cols)
archived_expr = _optional_col('archived', session_cols)
# Older/minimal state.db schemas can have NO ``messages`` table at all,
# or a ``messages`` table without a ``session_id`` / ``timestamp`` column.
# The projection SQL below joins ``messages`` and aggregates
@@ -793,6 +794,7 @@ def read_importable_agent_session_rows(
{parent_expr},
{ended_expr},
{end_reason_expr},
{archived_expr},
{actual_count_expr} AS actual_message_count,
{user_message_count_expr} AS actual_user_message_count,
{last_activity_expr} AS last_activity
+17 -5
View File
@@ -8073,7 +8073,7 @@ def _state_projection_sidecar_metadata(sid: str) -> dict:
stops being true (metadata moves to another store), this gate would short-
circuit before the real source — update both together.
"""
default = {"title": None, "archived": False}
default = {"title": None, "archived": None}
if not is_safe_session_id(sid):
return dict(default)
p = SESSION_DIR / f'{sid}.json'
@@ -8270,7 +8270,10 @@ def _load_cli_sessions_uncached(
_sidecar_meta = _state_projection_sidecar_metadata(sid)
if _sidecar_meta.get('title'):
_title = _sidecar_meta['title']
_archived = bool(_sidecar_meta.get('archived'))
if _sidecar_meta.get('archived') is not None:
_archived = bool(_sidecar_meta['archived'])
else:
_archived = bool(row.get('archived'))
_display_title = _title or f'{_source.title()} Session'
cli_sessions.append({
'session_id': sid,
@@ -8342,7 +8345,10 @@ def _load_cli_sessions_uncached(
_sidecar_meta = _state_projection_sidecar_metadata(sid)
if _sidecar_meta.get('title'):
_title = _sidecar_meta['title']
_archived = bool(_sidecar_meta.get('archived'))
if _sidecar_meta.get('archived') is not None:
_archived = bool(_sidecar_meta['archived'])
else:
_archived = bool(row.get('archived'))
_display_title = _title or 'Cron Session'
cli_sessions.append({
'session_id': sid,
@@ -8408,7 +8414,10 @@ def _load_cli_sessions_uncached(
_sidecar_meta = _state_projection_sidecar_metadata(sid)
if _sidecar_meta.get('title'):
_title = _sidecar_meta['title']
_archived = bool(_sidecar_meta.get('archived'))
if _sidecar_meta.get('archived') is not None:
_archived = bool(_sidecar_meta['archived'])
else:
_archived = bool(row.get('archived'))
_display_title = _title or 'Webhook Session'
cli_sessions.append({
'session_id': sid,
@@ -8473,7 +8482,10 @@ def _load_cli_sessions_uncached(
_sidecar_meta = _state_projection_sidecar_metadata(sid)
if _sidecar_meta.get('title'):
_title = _sidecar_meta['title']
_archived = bool(_sidecar_meta.get('archived'))
if _sidecar_meta.get('archived') is not None:
_archived = bool(_sidecar_meta['archived'])
else:
_archived = bool(row.get('archived'))
cli_sessions.append({
'session_id': sid,
'title': _title or 'Kanban Session',
+17
View File
@@ -606,6 +606,22 @@ def _session_list_cache_source_stamp(key: tuple) -> tuple[tuple[int, int], tuple
session_index_path = _session_list_cache_session_dir() / "_index.json"
except Exception:
session_index_path = None
all_profiles_state_stamp = None
if _cache_all_profiles:
try:
from api.models import _all_profiles_cli_contexts
contexts, _ = _all_profiles_cli_contexts()
all_profiles_state_stamp = tuple(
(
_session_list_cache_path_stamp(ctx_db),
_session_list_cache_path_stamp(ctx_db.with_name(f"{ctx_db.name}-wal") if ctx_db else None),
_session_list_cache_state_db_fingerprint(ctx_db),
)
for _home, ctx_db, _prof in contexts
)
except Exception:
all_profiles_state_stamp = None
return (
_session_list_cache_path_stamp(state_db_path),
_session_list_cache_path_stamp(state_db_wal_path),
@@ -617,6 +633,7 @@ def _session_list_cache_source_stamp(key: tuple) -> tuple[tuple[int, int], tuple
# frame size), so without this a freshly-committed CLI/gateway session
# could be served stale for the cache TTL. Mirrors the models-layer fix.
_session_list_cache_state_db_fingerprint(state_db_path),
all_profiles_state_stamp,
swv,
)