feat: real-time gateway session sync (Phase 1) (#274) - #279
Merged
Merged
Conversation
- Add gateway_watcher.py: background daemon polling state.db every 5s for gateway session changes (telegram, discord, slack, etc.) - Extend get_cli_sessions() to include all non-webui sources - Add SSE endpoint /api/sessions/gateway/stream for real-time push - Add dynamic source badges (telegram=blue, discord=purple, slack=dark purple) - Rename 'Show CLI sessions' to 'Show agent sessions' - Wire watcher lifecycle into server start/stop - 10 tests covering metadata, filtering, SSE, and watcher lifecycle - Activated via the same checkbox as CLI session import Addresses GitHub issue #272
- Fix critical SSE bug: frontend listened for 'gateway_session_update' but backend sends 'sessions_changed' -- events were silently dropped - Fix frontend field check: data.changed -> data.sessions (matches the actual payload structure from gateway_watcher) - Fix TLS: ssl.TLSv1_2 -> ssl.TLSVersion.TLSv1_2 (the bare attribute does not exist, would crash TLS setup and silently fall back to HTTP) - Remove PLAN.md: implementation plan should not be committed to repo Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
tests/test_gateway_sync.py: - Fix _get_test_state_dir() path mismatch: the function was computing HERMES_HOME/webui-mvp-test but conftest.py sets HERMES_HOME=TEST_STATE_DIR, so state.db was written to a double-nested path the server never read. Now uses HERMES_WEBUI_STATE_DIR first (which conftest sets directly to TEST_STATE_DIR), fixing the 7/10 test failures in full-suite ordering. - Fix conn cleanup: removed conn.close() from inside try blocks so the connection stays valid for _remove_test_sessions() in the finally block. Previously the closed conn caused ProgrammingError in finally (swallowed by bare except), leaving ghost sessions in state.db on test failure. api/gateway_watcher.py: - Fix slow-consumer queue eviction: when a subscriber queue fills (>10 events) and is removed from _subscribers, now puts a None sentinel into it so the SSE handler unblocks and closes the connection, letting EventSource auto-reconnect. Without this the connection stayed open but received no further events.
The gateway sync tests write directly to state.db and must use the same path the test server reads from. Previously they computed the path independently, which broke when test_auth_sessions.py set a different HERMES_WEBUI_STATE_DIR in the test-process environment at import time. tests/conftest.py: - Set HERMES_WEBUI_TEST_STATE_DIR=TEST_STATE_DIR in the test process's os.environ (via setdefault) so gateway tests can read it reliably. Using setdefault preserves any explicit override the caller may pass. tests/test_gateway_sync.py: - Simplify _get_test_state_dir(): check HERMES_WEBUI_TEST_STATE_DIR first (now reliably set by conftest), fall back to HERMES_HOME/webui-mvp-test. Remove the workaround that tried to snapshot HERMES_HOME at import time. Result: 658/658 tests pass in full-suite ordering (was 651 pass / 7 fail).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Agent review — APPROVED WITH FIXES ✅
Full diff, security audit, browser QA, and test suite completed.
Summary: Real-time gateway session sync — polls
state.dbevery 5s for Telegram/Discord/Slack sessions, pushes changes via SSE. Good architecture, comprehensive tests, 4 bugs fixed.Diff: 11 files, +702 additions
Security: CLEAN — no XSS, no external URLs, no subprocess, dataset property for source_tag (safe), SSE uses json.dumps
Tests: 658 passed, 0 failed (648 baseline + 10 new gateway sync tests)
Browser QA: ✅ Telegram/Discord/Slack sessions appear in sidebar with correct source badges, SSE endpoint returns
text/event-stream, zero console errors, settings label updated to "Show agent sessions"Bugs fixed (on top of other agent's 4 fixes):
Test state.db path mismatch (critical for CI) —
test_gateway_sync.pycomputedstate.dbpath independently buttest_auth_sessions.pycontaminatesHERMES_WEBUI_STATE_DIRat import time. Fixed by havingconftest.pysetHERMES_WEBUI_TEST_STATE_DIRin the test process'sos.environ(viasetdefault) so gateway tests always write to the path the server reads from. Result: 7/10 tests were failing in full-suite ordering — now 10/10 pass.Connection cleanup in test finally blocks — Tests called
conn.close()insidetry:then_remove_test_sessions(conn, ...)infinally:on the closed connection. ProgrammingError was silently swallowed, leaving ghost sessions in state.db on test failure.Slow-consumer SSE queue eviction is silent — When a subscriber queue fills (>10 events), the watcher removed it from
_subscribersbut left the SSE handler blocked onq.get(timeout=30). The connection stayed open but received no more events and EventSource never knew to reconnect. Fix: put aNonesentinel in the dead queue so the handler unblocks, closes, and lets EventSource auto-reconnect.Stale-base regression avoided: PR was cut from pre-v0.47.1 master. Direct merge would have deleted the Spanish locale (189 lines) and
test_spanish_locale.py(45 lines, 3 tests). Cherry-picked the two genuine commits onto current master instead.Reviewed branch:
feat/gateway-session-sync-reviewed(4 commits on top of current master)