Purpose: This page documents how the Hermes messaging gateway manages conversational sessions and multi-platform media. It covers session identity via composite keys, persistent storage using SQLite, media caching for vision/audio tools, and the interrupt handling mechanism that allows users to stop or redirect the agent mid-turn.
Scope: This document covers the GatewayRunner, SessionDB, SessionSource, and BasePlatformAdapter components. For the core conversation logic, see Core Agent. For specific platform configurations, see Platform Adapters.
The gateway identifies unique conversations using a composite key that incorporates the platform, user, and chat context. This ensures that a single user can maintain distinct conversation states across different groups or DM channels.
The SessionSource dataclass gateway/session.py148-180 tracks the origin of every message. This information is used to route responses back to the right place, inject context into the system prompt, and track origin for cron job delivery gateway/session.py150-155
| Component | Description | Example |
|---|---|---|
| Platform | The originating service (Enum) | telegram, discord, whatsapp gateway/session.py157 |
| Chat ID | Unique ID for the DM or Group | -100123456789 (TG), C12345 (Slack) gateway/session.py158 |
| Thread ID | Sub-context for forum topics or threads | Discord Thread ID, Slack thread_ts gateway/session.py163 |
| Chat Type | Classification of the chat | dm, group, channel, thread gateway/session.py160 |
The session_key is generated by combining these identifiers to ensure session isolation. Any value that could escape the sessions directory as a path (e.g., parent traversal ..) is rejected by _is_path_unsafe gateway/session.py108-120 For Telegram private-chat topics created by Hermes, the system ensures messages stay in the expected lane by including both the thread ID and a reply anchor gateway/platforms/base.py120-123
To help the agent understand its environment, the SessionSource is used to build a dynamic system prompt via build_session_context_prompt tests/gateway/test_session.py175-199 This prompt informs the agent about:
_hash_sender_id helper converts identifiers to user_<12hex> format gateway/session.py69-71Sources: gateway/session.py61-86 gateway/session.py108-120 gateway/session.py148-180 gateway/platforms/base.py120-123 tests/gateway/test_session.py175-199
Hermes uses a centralized SQLite database (state.db) for global search, metadata, and message history.
SessionDB)The SessionDB class hermes_state.py215-220 provides persistent session storage hermes_state.py3-15 It uses WAL (Write-Ahead Logging) mode for concurrent multi-platform access hermes_state.py10
To handle environments where WAL is incompatible (like NFS or SMB), the system detects locking protocol errors hermes_cli/sqlite_runtime.py33-35
Key Database Operations:
create_session(): Initializes a session record with metadata and model configuration tests/test_hermes_state.py85-98update_session_cwd(): Persists working directory, git branch, and repo root for the agent tests/test_hermes_state.py134-140_collect_delegate_child_ids(): Identifies subagent sessions for cascade-deletion hermes_state.py167-175The database uses the SQLite FTS5 module to index message content hermes_state.py11
messages_fts allow fast retrieval across all platform messages hermes_state.py11Diagram: Message persistence and FTS5 indexing flow
Sources: hermes_state.py3-15 hermes_state.py167-175 hermes_cli/sqlite_runtime.py33-35 tests/test_hermes_state.py57-63 tests/test_hermes_state.py85-98 tests/test_hermes_state.py134-140
The gateway handles multimodal inputs and provides progressive response streaming to messaging platforms.
The gateway identifies and strips internal media directives before displaying text to users.
MEDIA: tags and [[audio_as_voice]] directives are removed from display text via _clean_for_display gateway/session_context.py100-112UnicodeEncodeError hermes_state.py98-106cache_image_from_bytes, cache_audio_from_bytes, and cache_video_from_bytes gateway/platforms/base.py260-262 This ensures that media can be processed by tools or re-sent.gateway.max_inbound_media_bytes configuration limits the size of inbound media buffered into RAM to prevent resource exhaustion tests/gateway/test_platform_base.py41-42 validate_inbound_media_size enforces this limit gateway/platforms/base.py270-272should_send_media_as_audio determines if a media file should be sent using the platform's native audio sender, considering platform-specific formats (e.g., Telegram's MP3/M4A for sendAudio vs. Opus/OGG for sendVoice) gateway/platforms/base.py131-151GatewayStreamConsumer)The GatewayStreamConsumer bridges synchronous agent callbacks to asynchronous platform delivery gateway/session_context.py1-14
ensure_closed_code_fences automatically appends closing backticks if the model output is truncated gateway/session_context.py76-106edit (progressive editing) and draft (native platform drafts) gateway/session_context.py143-150Diagram: Media and Streaming Message Flow
Sources: gateway/session_context.py1-14 gateway/session_context.py7-9 gateway/session_context.py76-106 gateway/session_context.py100-112 gateway/session_context.py143-150 gateway/platforms/base.py131-151 gateway/platforms/base.py260-262 gateway/platforms/base.py270-272 hermes_state.py98-106 tests/gateway/test_platform_base.py41-42
When the gateway restarts, it manages "resume pending" states to ensure conversation continuity.
resume_pending=True tests/gateway/test_restart_resume_pending.py7-12auto_continue_freshness_window gateway/session.py31-58/voice command allows users to toggle between on, off, and tts modes tests/gateway/test_tts_media_routing.py10-12gateway_voice_mode.json gateway/config.py1000-1002_sync_voice_mode_state_to_adapter synchronizes these preferences with platform adapters gateway/config.py1004-1006The TelegramAdapter implements complex escaping for MarkdownV2 to prevent rendering failures.
_escape_mdv2 handles the 18 special characters required by Telegram gateway/platforms/base.py190-192utf16_len correctly counts UTF-16 code units, which is crucial for Telegram's message length limits (4096 UTF-16 code units) gateway/platforms/base.py154-167 _prefix_within_utf16_limit ensures text is truncated without breaking surrogate pairs gateway/platforms/base.py169-172Diagram: Session state transitions and interrupt handling
Sources: gateway/session.py31-58 gateway/session_context.py1-14 gateway/config.py1000-1002 gateway/config.py1004-1006 gateway/platforms/base.py154-167 gateway/platforms/base.py169-172 gateway/platforms/base.py190-192 gateway/platforms/base.py200-202 tests/gateway/test_restart_resume_pending.py7-12 tests/gateway/test_restart_resume_pending.py154-158 tests/gateway/test_tts_media_routing.py10-12
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.