Stage 376: PR #2457

# Conflicts:
#	CHANGELOG.md
This commit is contained in:
nesquena-hermes
2026-05-17 16:42:10 +00:00
5 changed files with 15 additions and 1 deletions
+1
View File
@@ -12,6 +12,7 @@
- **PR #2450** by @Michaelyklam (fixes #2447) — Cap the optional streaming word-fade drain after the final `done` SSE event so very large or bursty completed responses are rendered from the canonical session promptly instead of keeping the chat in a live/working state until Stop is pressed.
- **PR #2452** by @Michaelyklam (fixes #2451) — Manual WebUI cron triggers now deliver the same final response or failure notice as scheduled cron runs, while still saving output files and recording delivery errors separately from job execution failures.
- Keep the sidebar spinner in sync with server session metadata when the currently open session has finished but the browser still has stale local busy state (#2454).
- **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)
+2
View File
@@ -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',
+1
View File
@@ -4240,6 +4240,7 @@ def handle_get(handler, parsed) -> bool:
"telegram": "Telegram",
"discord": "Discord",
"slack": "Slack",
"email": "Email",
"web": "Web",
"api": "API",
}
+2 -1
View File
@@ -767,12 +767,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) {
+9
View File
@@ -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.