Skip to content

fix: batch gateway/platform fixes — matrix E2EE, CJK input, Windows browser, Feishu reconnect + ACL - #5665

Merged
teknium1 merged 10 commits into
mainfrom
hermes/hermes-03d7aa21
Apr 6, 2026
Merged

teknium1 merged 10 commits into
mainfrom
hermes/hermes-03d7aa21

Conversation

@teknium1

@teknium1 teknium1 commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Five gateway/platform fixes salvaged from contributor PRs (Tier 3 from batch triage).

1. Matrix E2EE hard-fail + stable device ID (PR #5517 by @kshitijk4poor)

  • Previously: if MATRIX_ENCRYPTION=true but python-olm missing, silently fell back to plaintext
  • Now: hard-fails in check_matrix_requirements() and connect() — no silent degradation
  • Adds MATRIX_DEVICE_ID config key for stable device identification
  • 8 new test methods

2. CJK wide chars in TUI input height (PR #5539 by @qaqcvc)

  • len() counts CJK characters as 1 but they occupy 2 terminal columns
  • Surgical fix in _input_height(): uses get_cwidth() from prompt_toolkit
  • Only 8 lines changed in the 8500-line cli.py, wrapped in try/except fallback

3. Windows browser auto-launch (PR #5584 by @Ruzzgar)

  • Extracted browser discovery into _get_chrome_debug_candidates()
  • Adds Windows support: PATH lookup + common install dirs (Chrome, Edge, Brave, Chromium)
  • Fixed cross-platform test: use os.path.join instead of hardcoded backslash paths

4. Feishu reconnect/shutdown (PR #5500 by @jtuki, 5 commits)

  • Event handler captured stale loop references across reconnects → message drops
  • Shutdown hung because websocket thread loop wasn't cleanly stopped
  • Fix: rebuild handler on each connect(), proper lifecycle management, configurable reconnect/ping timing

5. Feishu per-group access control (PR #5541 by @jtuki)

  • Adds per-group policy control: open, disabled, allowlist, blacklist, admin_only
  • Global admins bypass all group rules
  • Resolved merge conflict with Fix/feishu reconnect and shutdown #5500 in FeishuAdapterSettings fields + _load_settings

Dropped from this batch: PR #5572 (pairing file locks) — main-side commit e9b5864 already added atomic writes + threading.RLock to pairing.py, creating 5 conflict regions. #5572's unique addition (cross-process fcntl/msvcrt locks) can be a follow-up PR.

Test results

  • 251/258 targeted tests pass (7 pre-existing matrix failures from missing nio dep)
  • All files compile clean

Closes #5517, closes #5539, closes #5584, closes #5500, closes #5541

kshitijk4poor and others added 10 commits April 6, 2026 16:51
…EVICE_ID

Two issues caused Matrix E2EE to silently not work in encrypted rooms:

1. When matrix-nio is installed without the [e2e] extra (no python-olm /
   libolm), nio.crypto.ENCRYPTION_ENABLED is False and client.olm is
   never initialized. The adapter logged warnings but returned True from
   connect(), so the bot appeared online but could never decrypt messages.
   Now: check_matrix_requirements() and connect() both hard-fail with a
   clear error message when MATRIX_ENCRYPTION=true but E2EE deps are
   missing.

2. Without a stable device_id, the bot gets a new device identity on each
   restart. Other clients see it as "unknown device" and refuse to share
   Megolm session keys. Now: MATRIX_DEVICE_ID env var lets users pin a
   stable device identity that persists across restarts and is passed to
   nio.AsyncClient constructor + restore_login().

Changes:
- gateway/platforms/matrix.py: add _check_e2ee_deps(), hard-fail in
  connect() and check_matrix_requirements(), MATRIX_DEVICE_ID support
  in constructor + restore_login
- gateway/config.py: plumb MATRIX_DEVICE_ID into platform extras
- hermes_cli/config.py: add MATRIX_DEVICE_ID to OPTIONAL_ENV_VARS

Closes #3521
This commit fixes two critical bugs in the Feishu adapter that affect
message reliability and process lifecycle.

**Bug Fix 1: Intermittent Message Drops**

Root cause: Event handler was created once in __init__ and reused across
reconnects, causing callbacks to capture stale loop references. When the
adapter disconnected and reconnected, old callbacks continued firing with
invalid loop references, resulting in dropped messages with warnings:
"[Feishu] Dropping inbound message before adapter loop is ready"

Fix:
- Rebuild event handler on each connect (websocket/webhook)
- Clear handler on disconnect
- Ensure callbacks always capture current valid loop
- Add defensive loop.is_closed() checks with getattr for test compatibility
- Unify webhook dispatch path to use same loop checks as websocket mode

**Bug Fix 2: Process Hangs on Ctrl+C / SIGTERM**

Root cause: Feishu SDK's websocket client runs in a background thread with
an infinite _select() loop that never exits naturally. The thread was never
properly joined on disconnect, causing processes to hang indefinitely after
Ctrl+C or gateway stop commands.

Fix:
- Store reference to thread-local event loop (_ws_thread_loop)
- On disconnect, cancel all tasks in thread loop and stop it gracefully
  via call_soon_threadsafe()
- Await thread future with 10s timeout
- Clean up pending tasks in thread's finally block before closing loop
- Add detailed debug logging for disconnect flow

**Additional Improvements:**
- Add regression tests for disconnect cleanup and webhook dispatch
- Ensure all event callbacks check loop readiness before dispatching

Tested on Linux with websocket mode. All Feishu tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow users to configure websocket reconnect behavior via platform extra
config to reduce reconnect latency in production environments.

The official Feishu SDK defaults to:
- First reconnect: random jitter 0-30 seconds
- Subsequent retries: 120 second intervals

This can cause 20-30 second delays before reconnection after network
interruptions. This commit makes these values configurable while keeping
the SDK defaults for backward compatibility.

Configuration via ~/.hermes/config.yaml:
```yaml
platforms:
  feishu:
    extra:
      ws_reconnect_nonce: 0        # Disable first-reconnect jitter (default: 30)
      ws_reconnect_interval: 3     # Retry every 3 seconds (default: 120)
```

Invalid values (negative numbers, non-integers) fall back to SDK defaults.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow Feishu websocket keepalive timing to be configured via platform
extra config so disconnects can be detected faster in unstable networks.

New optional extra settings:
- ws_ping_interval
- ws_ping_timeout

These values are applied only when explicitly configured. Invalid values
fall back to the websocket library defaults by leaving the options unset.

This complements the reconnect timing settings added previously and helps
reduce total recovery time after network interruptions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reapply local reconnect and ping settings after the Feishu SDK refreshes its client config so user-provided websocket tuning actually takes effect.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consolidate coercion functions, extract loop readiness check, and deduplicate test mock setup to improve maintainability without changing behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add fine-grained authorization policies per Feishu group chat via
platforms.feishu.extra configuration.

- Add global bot-level admins that bypass all group restrictions
- Add per-group policies: open, allowlist, blacklist, admin_only, disabled
- Add default_group_policy fallback for chats without explicit rules
- Thread chat_id through group message gate for per-chat rule selection
- Match both open_id and user_id for backward compatibility
- Preserve existing FEISHU_ALLOWED_USERS / FEISHU_GROUP_POLICY behavior
- Add focused regression tests for all policy modes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use os.path.join for Windows install path so test passes on Linux
(os.path.join uses / on Linux, \ on Windows).
@teknium1
teknium1 force-pushed the hermes/hermes-03d7aa21 branch from ca724af to 3e26865 Compare April 6, 2026 23:53
@teknium1 teknium1 changed the title fix: batch gateway/platform fixes — pairing locks, matrix E2EE, CJK input, Windows browser, Feishu reconnect + ACL fix: batch gateway/platform fixes — matrix E2EE, CJK input, Windows browser, Feishu reconnect + ACL Apr 6, 2026
@teknium1
teknium1 merged commit adb418f into main Apr 6, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants