From f56ec1ec35dba1052ac91bac48bb1043d630fd33 Mon Sep 17 00:00:00 2001 From: Michael Lam Date: Sun, 17 May 2026 02:48:40 -0700 Subject: [PATCH] fix: label email gateway sessions --- CHANGELOG.md | 4 ++++ api/agent_sessions.py | 2 ++ api/routes.py | 1 + static/sessions.js | 3 ++- tests/test_gateway_sync.py | 9 +++++++++ 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93fb8cdd..002b487b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- **PR #2457** by @Michaelyklam (closes #2456) — Email gateway sessions imported from Hermes Agent `state.db` now normalize as messaging sessions and show an `Email` source label in the WebUI sidebar instead of falling through as unlabelled generic agent sessions. Keeps the Python source-normalization contract, gateway status platform labels, and frontend handoff/sidebar whitelist in sync. + ## [v0.51.82] — 2026-05-17 — Release BF (stage-375 — 2-PR batch — table renderer pipe protection + Catppuccin appearance skin) ### Added diff --git a/api/agent_sessions.py b/api/agent_sessions.py index 41556fad..641e3a22 100644 --- a/api/agent_sessions.py +++ b/api/agent_sessions.py @@ -9,6 +9,7 @@ logger = logging.getLogger(__name__) MESSAGING_SOURCES = { 'discord', + 'email', 'slack', 'telegram', 'weixin', @@ -22,6 +23,7 @@ SOURCE_LABELS = { 'cli': 'CLI', 'cron': 'Cron', 'discord': 'Discord', + 'email': 'Email', 'slack': 'Slack', 'telegram': 'Telegram', 'tool': 'Tool', diff --git a/api/routes.py b/api/routes.py index 677a6677..d610e02f 100644 --- a/api/routes.py +++ b/api/routes.py @@ -4183,6 +4183,7 @@ def handle_get(handler, parsed) -> bool: "telegram": "Telegram", "discord": "Discord", "slack": "Slack", + "email": "Email", "web": "Web", "api": "API", } diff --git a/static/sessions.js b/static/sessions.js index 1665ee8f..3de27f4f 100644 --- a/static/sessions.js +++ b/static/sessions.js @@ -742,12 +742,13 @@ const _HANDOFF_THRESHOLD = 10; // conversation rounds const _HANDOFF_STORAGE_PREFIX = 'handoff:'; const _HANDOFF_SUFFIX_DISMISSED_AT = 'dismissed_at'; const _HANDOFF_SUFFIX_SUMMARY_HANDLED_AT = 'summary_handled_at'; -const _MESSAGING_RAW_SOURCES = new Set(['weixin', 'telegram', 'discord', 'slack']); +const _MESSAGING_RAW_SOURCES = new Set(['weixin', 'telegram', 'discord', 'slack', 'email']); const _MESSAGING_SOURCE_LABELS = { weixin: 'WeChat', telegram: 'Telegram', discord: 'Discord', slack: 'Slack', + email: 'Email', }; function _isMessagingSession(session) { diff --git a/tests/test_gateway_sync.py b/tests/test_gateway_sync.py index d364606e..75fedb2b 100644 --- a/tests/test_gateway_sync.py +++ b/tests/test_gateway_sync.py @@ -797,6 +797,7 @@ def test_agent_session_source_normalization_contract(): cases = { 'cli': ('cli', 'CLI'), + 'email': ('messaging', 'Email'), 'weixin': ('messaging', 'Weixin'), 'telegram': ('messaging', 'Telegram'), 'discord': ('messaging', 'Discord'), @@ -818,6 +819,14 @@ def test_agent_session_source_normalization_contract(): assert normalized['raw_source'] is None +def test_sessions_js_treats_email_as_messaging_source(): + """Email gateway sessions should receive the same sidebar metadata as other messaging channels.""" + src = (REPO_ROOT / "static" / "sessions.js").read_text(encoding="utf-8") + + assert "'email'" in src[src.find("_MESSAGING_RAW_SOURCES"):src.find("function _isMessagingSession")] + assert "email: 'Email'" in src[src.find("_MESSAGING_SOURCE_LABELS"):src.find("function _isMessagingSession")] + + 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.