fix(config+telegram): prevent duplicate config key and duplicate message delivery (#71047) - #71076
Conversation
…on (NousResearch#71067) _CryptoStateStore.get_encryption_info only consulted mautrix's in-memory MemoryStateStore, which has no record of m.room.encryption for rooms the bot joined in the past (the raw-sync path never feeds those state events through set_encryption_info). On a fresh crypto store this returns None for all previously-joined rooms, so OlmMachine reports them as unencrypted, never tracks peer devices, and silently drops all inbound messages. Fix: pass the mautrix Client into _CryptoStateStore so get_encryption_info can fall back to a live GET /_matrix/client/v3/rooms/{room_id}/state/ m.room.encryption query when the in-memory store returns None. The result is cached back via set_encryption_info so subsequent lookups (and OlmMachine device tracking) hit the fast path.
…age delivery (NousResearch#71047) Problem A: `hermes config set platforms.telegram.streaming false` appended a new top-level `platforms:` block instead of editing the existing one, because set_config_value navigated on the raw user config which lacks DEFAULT_CONFIG-only subtrees (platforms). The gateway reads the first block, so the change had no runtime effect. Fix: use load_config() (merged with defaults) as the navigation base so keys present only in defaults are found by _set_nested. Write back only the raw user-set keys via atomic_yaml_write as before. Problem B: When streaming + reply_to_mode='first' and the final edit fails (flood control), the fallback resend (via _send_fallback_final and _send_empty_fallback_final) sent the completed answer as a fresh non-reply message, producing two visible messages — the streamed reply preview and the plain resend. Fix: preserve the reply anchor by passing reply_to=self._initial_reply_to_id on every fallback- and continuation- send path, matching the first-send path at line 2224 that already passes it.
9a4f803 to
e4217ef
Compare
|
Thank you for tracing both delivery and config behavior. The Telegram fallback direction is useful, but the PR needs a focused rework before it can be salvaged. Problems
Suggested changes
This is an automated hermes-sweeper review. |
|
Heads up: I opened #78111 as a focused fix for only Problem A of #71047 (the #78111 redirects If the maintainers prefer to consolidate on a single PR, #78111's |
Fixes #71047
Problem A —
hermes config setduplicates top-level config keyRunning
hermes config set platforms.telegram.streaming falseappended a newplatforms:block at EOF instead of editing the existing one, becauseset_config_valuenavigated on the raw user config (stripped of DEFAULT_CONFIG-only subtrees likeplatforms). The gateway reads the first block, soconfig sethad no runtime effect — a silent, confusing failure.Fix: Use
load_config()(merged with DEFAULT_CONFIG) as the navigation base for_set_nested, so keys present only in defaults are found and mutated in-place. Write back only the raw user-set keys viaatomic_yaml_writeas before, preserving the contract of not dumping defaults.Problem B — Streaming +
reply_to_mode='first'duplicates final messageWhen
streaming: trueandreply_to_mode: 'first', the streamed preview is sent as a reply to the user. If the final edit fails (flood control), the fallback paths (_send_fallback_finaland_send_empty_fallback_final) sent the completed answer as a fresh non-reply message, producing two visible messages — the reply-preview and the plain resend.Fix: Preserve the reply anchor by passing
reply_to=self._initial_reply_to_idon every fallback/continuationadapter.send()call, matching the first-send path at line 2224 that already passes it.Files changed
hermes_cli/config.pyload_config()as navigation base inset_config_value; write back raw configgateway/stream_consumer.pyreply_to=self._initial_reply_to_idon fallback send + continuation chunk sendtests/gateway/test_telegram_final_delivery.pyreply_tokwarg inadapter.sendcallsTests
tests/hermes_cli/test_set_config_value.py: 91/91 passedtests/hermes_cli/test_config.py: 186/186 passedtests/gateway/test_telegram_final_delivery.py: 10/10 passedtests/gateway/: 301 passed, 1 pre-existing failure (Honcho cache busting), 1 skipped