Skip to content

fix(gateway): keep Telegram topic bindings aligned with compression children#34409

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-234d411e
May 29, 2026
Merged

fix(gateway): keep Telegram topic bindings aligned with compression children#34409
teknium1 merged 1 commit into
mainfrom
hermes/hermes-234d411e

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Telegram DM topic conversations no longer get stuck in compression loops or reload pre-compression parent transcripts.

When context compression rotates session_entry.session_id mid-turn, the (chat_id, thread_id) → session_id row in SQLite stayed pointed at the parent. The next inbound message in that topic loaded the oversized parent transcript and re-ran preflight compression — sometimes in a loop.

Closes #20470, #29712, #33414.

Changes

  • gateway/run.py: new _sync_telegram_topic_binding(source, entry, *, reason) helper called after each of the three session_entry.session_id = ... rotation sites (hygiene compression, agent-result compression rotation, /compress command).
  • gateway/run.py: read-path self-heal — when an existing binding is found, walk SessionDB.get_compression_tip() forward and switch_session to the descendant. Rewrites the binding row to the tip so subsequent messages skip the walk. Heals already-stale state on next user message; no restart required.
  • tests/gateway/test_telegram_topic_mode.py: regression test exercises the full inbound flow with a real SessionDB + parent→child compression chain; verifies the route advances to the child and the binding row is rewritten.

Skipped from competitor PRs (intentionally)

Validation

Before After
New regression test fails (switch_session called with parent-session) passes (called with child-session, binding rewritten)
tests/gateway/test_telegram_topic_mode.py 43 pass 44 pass
Full tests/gateway/ (5,974 tests) n/a 100% pass
LOC n/a +150 / -0 across 2 files

Synthesis credit

Reviewed all six competing PRs to settle on the minimal load-bearing fix; closing each with credit:

Infographic

infographic

…hildren

Telegram DM topic bindings persist (chat_id, thread_id) -> session_id in
SQLite so reopening a topic resumes the right Hermes session. When
compression rotated session_entry.session_id mid-turn, the binding row
stayed pointed at the pre-compression parent. On the next inbound
message in that topic the gateway reloaded the oversized parent
transcript, retriggering preflight compression — sometimes in a loop.

Two-pronged fix:

1. `_sync_telegram_topic_binding(source, entry, *, reason)` helper
   called immediately after each of the three session_id rotation sites
   in _handle_message_with_agent (hygiene compression, agent-result
   compression rotation, /compress command). Keeps future bindings
   fresh.

2. Read-path self-heal: when resolving an existing topic binding, walk
   SessionDB.get_compression_tip() forward and switch_session to the
   descendant instead of the stored parent. Rewrites the binding row to
   the tip so subsequent messages skip the walk. Heals existing stale
   state on the next user message without requiring a gateway restart.

Skipped from competing PRs as not load-bearing for the bug:
- advance_session_after_compression SessionStore primitive (#26204/
  #28870/#33416) — preserves end_reason='compression' analytics nicety
  but doesn't affect routing correctness.
- Cached-agent eviction on session_id mismatch — _compress_context()
  already mutates tmp_agent.session_id on the cached object so the
  in-memory agent self-corrects.
- Startup repair pass (#33416) — redundant once the read path heals on
  the next message; one-line CLI follow-up can address bindings for
  topics users never reopen.

Closes #20470, #29712, #33414. Acknowledges work in #23195
(@litvinovvo), #26204 (@bizyumov), #28870 (@donrhmexe), #29713
(@hehehe0803), #29945 (@eugeneb1ack), #33416 (@bizyumov).
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-234d411e vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9419 on HEAD, 9419 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 4890 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@teknium1 teknium1 merged commit db96fc6 into main May 29, 2026
25 checks passed
@teknium1 teknium1 deleted the hermes/hermes-234d411e branch May 29, 2026 06:25
@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter P1 High — major feature broken, no workaround labels May 29, 2026
KKT-OPT pushed a commit to KKT-OPT/hermes-agent that referenced this pull request May 31, 2026
…hildren (NousResearch#34409)

Telegram DM topic bindings persist (chat_id, thread_id) -> session_id in
SQLite so reopening a topic resumes the right Hermes session. When
compression rotated session_entry.session_id mid-turn, the binding row
stayed pointed at the pre-compression parent. On the next inbound
message in that topic the gateway reloaded the oversized parent
transcript, retriggering preflight compression — sometimes in a loop.

Two-pronged fix:

1. `_sync_telegram_topic_binding(source, entry, *, reason)` helper
   called immediately after each of the three session_id rotation sites
   in _handle_message_with_agent (hygiene compression, agent-result
   compression rotation, /compress command). Keeps future bindings
   fresh.

2. Read-path self-heal: when resolving an existing topic binding, walk
   SessionDB.get_compression_tip() forward and switch_session to the
   descendant instead of the stored parent. Rewrites the binding row to
   the tip so subsequent messages skip the walk. Heals existing stale
   state on the next user message without requiring a gateway restart.

Skipped from competing PRs as not load-bearing for the bug:
- advance_session_after_compression SessionStore primitive (NousResearch#26204/
  NousResearch#28870/NousResearch#33416) — preserves end_reason='compression' analytics nicety
  but doesn't affect routing correctness.
- Cached-agent eviction on session_id mismatch — _compress_context()
  already mutates tmp_agent.session_id on the cached object so the
  in-memory agent self-corrects.
- Startup repair pass (NousResearch#33416) — redundant once the read path heals on
  the next message; one-line CLI follow-up can address bindings for
  topics users never reopen.

Closes NousResearch#20470, NousResearch#29712, NousResearch#33414. Acknowledges work in NousResearch#23195
(@litvinovvo), NousResearch#26204 (@bizyumov), NousResearch#28870 (@donrhmexe), NousResearch#29713
(@hehehe0803), NousResearch#29945 (@eugeneb1ack), NousResearch#33416 (@bizyumov).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround platform/telegram Telegram bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Telegram DM topic binding not refreshed after compression-induced session split — causes preflight compression loop

2 participants