fix: keep cross-source continuations separate in sidebar

This commit is contained in:
Manfred committed 2026-05-04 09:30:47 +02:00
1 parent 9986d2fd30
commit 3c93d5a702
2 files changed
+68 -1

No files matched your search

+13 -1
View File
@@ -79,9 +79,18 @@ def _is_continuation_session(parent: dict | None, child: dict | None) -> bool:
should continue the same visible conversation rather than becoming a
separate child-session row. Plain parent/child links that started before the
parent's ended boundary remain child sessions.
Do not collapse lineage across raw sources. A WebUI session that continues
from a Telegram/CLI/etc. parent must remain visible as its own surface-owned
conversation; otherwise the tip inherits the root's title/source metadata and
can disappear under messaging/sidebar policies.
"""
if not parent or not child:
return False
parent_source = str(parent.get('source') or '').strip().lower()
child_source = str(child.get('source') or '').strip().lower()
if parent_source and child_source and parent_source != child_source:
return False
if parent.get('end_reason') not in {'compression', 'cli_close'}:
return False
ended_at = parent.get('ended_at')
@@ -133,10 +142,13 @@ def _project_agent_session_rows(rows: list[dict]) -> list[dict]:
if not parent_id:
continue
children_by_parent.setdefault(parent_id, []).append(row)
if _is_continuation_session(rows_by_id.get(parent_id), row):
parent = rows_by_id.get(parent_id)
if _is_continuation_session(parent, row):
continuation_child_ids.add(row['id'])
else:
row['relationship_type'] = 'child_session'
row['parent_title'] = parent.get('title') if parent else None
row['parent_source'] = parent.get('source') if parent else None
parent_root = _continuation_root_id(rows_by_id, parent_id)
if parent_root:
row['_parent_lineage_root_id'] = parent_root
+55
View File
@@ -773,6 +773,61 @@ def test_agent_session_source_normalization_contract():
assert normalized['raw_source'] is None
def test_cross_source_parent_child_is_not_collapsed_into_root_metadata(cleanup_test_sessions):
"""A WebUI continuation from a messaging parent must keep WebUI metadata.
Regression for a production case where a WebUI session continued from a
Telegram compression chain and was projected as the old Telegram root,
inheriting the wrong title/source and hiding from the expected sidebar view.
"""
from api.agent_sessions import read_importable_agent_session_rows
conn = _ensure_state_db()
root_sid = 'gw_tg_cross_source_root_001'
webui_sid = 'webui_cross_source_tip_001'
now = time.time()
cleanup_test_sessions.extend([root_sid, webui_sid])
try:
_insert_agent_session_row(
conn,
session_id=root_sid,
source='telegram',
title='Old Telegram Root',
started_at=now - 20,
ended_at=now - 10,
end_reason='compression',
messages=2,
)
_insert_agent_session_row(
conn,
session_id=webui_sid,
source='webui',
title='Current WebUI Work',
started_at=now - 9,
parent_session_id=root_sid,
messages=2,
)
rows = read_importable_agent_session_rows(_get_state_db_path(), exclude_sources=None)
by_id = {row['id']: row for row in rows}
assert webui_sid in by_id
assert root_sid in by_id
webui = by_id[webui_sid]
assert webui.get('title') == 'Current WebUI Work'
assert webui.get('source') == 'webui'
assert webui.get('session_source') == 'webui'
assert webui.get('source_label') == 'WebUI'
assert webui.get('relationship_type') == 'child_session'
assert webui.get('parent_title') == 'Old Telegram Root'
finally:
try:
_remove_test_sessions(conn, root_sid, webui_sid)
conn.close()
except Exception:
pass
def test_gateway_watcher_uses_normalized_source_metadata(monkeypatch):
"""SSE snapshots use the same normalized source contract as /api/sessions."""
conn = _ensure_state_db()