Skip to content

fix(telegram): preserve busy-session queue payloads - #13913

Closed
ypwcharles wants to merge 3 commits into
NousResearch:mainfrom
ypwcharles:pr/telegram-busy-command-batching
Closed

fix(telegram): preserve busy-session queue payloads#13913
ypwcharles wants to merge 3 commits into
NousResearch:mainfrom
ypwcharles:pr/telegram-busy-command-batching

Conversation

@ypwcharles

@ypwcharles ypwcharles commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • preserve /queue media/reply metadata when a busy session queues the next turn
  • batch long Telegram slash commands (/queue, /background, /btw, /plan) so split follow-up chunks stay attached to the original command
  • route busy-session bypass handling through canonical command resolution and restore dedicated active-session bypass imports

Why

Telegram can split long slash-command messages client-side. The first chunk arrives as a command update, but continuation chunks arrive as plain text. Without batching and canonical busy-session handling, queued prompts could lose media payloads or treat continuation chunks as a brand-new follow-up.

Validation run locally

Local test runs used the repo's declared dev test stack from pyproject.toml (pytest, pytest-asyncio, pytest-xdist) via:

  • Python: /home/yangp/.hermes/hermes-agent/venv/bin/python3
  • Pytest: /home/yangp/.hermes/hermes-agent/venv/lib/python3.11/site-packages/pytest (9.0.3)

PR-focused regression coverage

  • python3 -m pytest tests/gateway/test_busy_session_bypass_race.py tests/gateway/test_telegram_text_batching.py tests/gateway/test_base_topic_sessions.py -v
    • Result: 26 passed
  • python3 -m pytest tests/gateway/test_session_race_guard.py tests/gateway/test_busy_session_bypass_race.py tests/gateway/test_telegram_text_batching.py tests/gateway/test_base_topic_sessions.py -q
    • Result: 42 passed
  • python3 -m pytest tests/gateway/test_discord_send.py tests/gateway/test_send_image_file.py -q
    • Result: 38 passed

Full suite context

  • python3 -m pytest tests/ -v
    • Result in this WSL2/Linux environment after the regression fix: 14074 passed, 75 failed, 35 skipped
    • Several remaining failures reproduce on upstream/main in the same environment and do not appear unique to this PR, including failures in tests/tools/test_voice_mode.py, tests/tools/test_browser_camofox.py, tests/tools/test_write_deny.py, tests/tools/test_zombie_process_cleanup.py, tests/gateway/test_agent_cache.py, tests/run_agent/test_real_interrupt_subagent.py, and parts of tests/gateway/test_approve_deny_commands.py.

Platforms tested

  • Linux (WSL2, Python 3.11)

@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter labels Apr 22, 2026
@ypwcharles

Copy link
Copy Markdown
Contributor Author

Supplemental validation note: local test runs above used the repo's declared dev pytest environment from pyproject.toml via /home/yangp/.hermes/hermes-agent/venv/bin/python3 (pytest 9.0.3).

GitHub Actions for this fork PR are currently in action_required state on the upstream repo side, so no check runs have started yet. Could a maintainer please approve the workflows for this PR so CI can run? Thank you.

@ypwcharles

Copy link
Copy Markdown
Contributor Author

Related upstream context: this PR overlaps with the same busy-session slash-command problem area as #6252 and #10370 (active-session bypass / non-interrupting slash-command handling in gateway/platforms/base.py and gateway/run.py).

The additional scope here is Telegram-specific:

  • batching long Telegram slash commands when the client splits them into a command chunk plus plain-text continuation chunks
  • preserving queued /queue media/reply metadata during busy-session handoff

So this is not intended as a duplicate of those PRs; it is meant to close the Telegram split/payload preservation gap in the same area.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jun 29, 2026
teknium1 added a commit that referenced this pull request Jul 1, 2026
/queue rebuilt the queued MessageEvent with only text/type/source/
message_id/channel_prompt, silently dropping any photo, document, voice,
or reply context attached to the command. The deferred turn then ran with
the attachment lost. Carry the full payload through, and accept a /queue
that has media but no prompt text (e.g. "/queue" as an image caption).

Salvaged from #13913 by @ypwcharles — the gateway busy-session/queue
infrastructure was rewritten since that PR (Telegram moved to
plugins/platforms/, /queue now uses the FIFO chain), so the media fix is
reimplemented against the current handler; the PR's batching and
busy-bypass changes targeted code paths that no longer exist.

Co-authored-by: ypwcharles <92324143+ypwcharles@users.noreply.github.com>
@teknium1

teknium1 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for this — the media-loss half of it was a genuine bug and your report is what surfaced it.

Merged the fix via #55960 (commit 7de48570 on main), with your authorship preserved as co-author.

Since April the gateway busy-session/queue subsystem was rewritten: Telegram moved out of gateway/platforms/telegram.py into plugins/platforms/telegram/, and /queue now runs through a FIFO chain (_enqueue_fifo / _queued_events). So the _busy_session_bypass attribute and the Telegram command-batching hook in this PR target code paths that no longer exist. What carried forward cleanly is the core fix: the /queue handler was rebuilding the queued MessageEvent with only text/type/source/message_id/channel_prompt and dropping media_urls, media_types, raw_message, and the reply_to_* fields. #55960 reimplements that against the current handler and also accepts a media-only /queue.

Closing this in favor of #55960#55960 — credited to you. Appreciate the catch!

@teknium1 teknium1 closed this Jul 1, 2026
@ypwcharles

Copy link
Copy Markdown
Contributor Author

Thanks for this — the media-loss half of it was a genuine bug and your report is what surfaced it.

Merged the fix via #55960 (commit 7de48570 on main), with your authorship preserved as co-author.

Since April the gateway busy-session/queue subsystem was rewritten: Telegram moved out of gateway/platforms/telegram.py into plugins/platforms/telegram/, and /queue now runs through a FIFO chain (_enqueue_fifo / _queued_events). So the _busy_session_bypass attribute and the Telegram command-batching hook in this PR target code paths that no longer exist. What carried forward cleanly is the core fix: the /queue handler was rebuilding the queued MessageEvent with only text/type/source/message_id/channel_prompt and dropping media_urls, media_types, raw_message, and the reply_to_* fields. #55960 reimplements that against the current handler and also accepts a media-only /queue.

Closing this in favor of #55960#55960 — credited to you. Appreciate the catch!

Thanks for the fix and for keeping the co-author attribution. I’ll pull latest and verify the /queue media/media-only cases on my Telegram setup.

dtera pushed a commit to dtera/hermes-agent that referenced this pull request Jul 1, 2026
/queue rebuilt the queued MessageEvent with only text/type/source/
message_id/channel_prompt, silently dropping any photo, document, voice,
or reply context attached to the command. The deferred turn then ran with
the attachment lost. Carry the full payload through, and accept a /queue
that has media but no prompt text (e.g. "/queue" as an image caption).

Salvaged from NousResearch#13913 by @ypwcharles — the gateway busy-session/queue
infrastructure was rewritten since that PR (Telegram moved to
plugins/platforms/, /queue now uses the FIFO chain), so the media fix is
reimplemented against the current handler; the PR's batching and
busy-bypass changes targeted code paths that no longer exist.

Co-authored-by: ypwcharles <92324143+ypwcharles@users.noreply.github.com>
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
/queue rebuilt the queued MessageEvent with only text/type/source/
message_id/channel_prompt, silently dropping any photo, document, voice,
or reply context attached to the command. The deferred turn then ran with
the attachment lost. Carry the full payload through, and accept a /queue
that has media but no prompt text (e.g. "/queue" as an image caption).

Salvaged from NousResearch#13913 by @ypwcharles — the gateway busy-session/queue
infrastructure was rewritten since that PR (Telegram moved to
plugins/platforms/, /queue now uses the FIFO chain), so the media fix is
reimplemented against the current handler; the PR's batching and
busy-bypass changes targeted code paths that no longer exist.

Co-authored-by: ypwcharles <92324143+ypwcharles@users.noreply.github.com>
Jasper6439 pushed a commit to Jasper6439/hermes-agent that referenced this pull request Jul 5, 2026
/queue rebuilt the queued MessageEvent with only text/type/source/
message_id/channel_prompt, silently dropping any photo, document, voice,
or reply context attached to the command. The deferred turn then ran with
the attachment lost. Carry the full payload through, and accept a /queue
that has media but no prompt text (e.g. "/queue" as an image caption).

Salvaged from NousResearch#13913 by @ypwcharles — the gateway busy-session/queue
infrastructure was rewritten since that PR (Telegram moved to
plugins/platforms/, /queue now uses the FIFO chain), so the media fix is
reimplemented against the current handler; the PR's batching and
busy-bypass changes targeted code paths that no longer exist.

Co-authored-by: ypwcharles <92324143+ypwcharles@users.noreply.github.com>
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
/queue rebuilt the queued MessageEvent with only text/type/source/
message_id/channel_prompt, silently dropping any photo, document, voice,
or reply context attached to the command. The deferred turn then ran with
the attachment lost. Carry the full payload through, and accept a /queue
that has media but no prompt text (e.g. "/queue" as an image caption).

Salvaged from NousResearch#13913 by @ypwcharles — the gateway busy-session/queue
infrastructure was rewritten since that PR (Telegram moved to
plugins/platforms/, /queue now uses the FIFO chain), so the media fix is
reimplemented against the current handler; the PR's batching and
busy-bypass changes targeted code paths that no longer exist.

Co-authored-by: ypwcharles <92324143+ypwcharles@users.noreply.github.com>
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
/queue rebuilt the queued MessageEvent with only text/type/source/
message_id/channel_prompt, silently dropping any photo, document, voice,
or reply context attached to the command. The deferred turn then ran with
the attachment lost. Carry the full payload through, and accept a /queue
that has media but no prompt text (e.g. "/queue" as an image caption).

Salvaged from NousResearch#13913 by @ypwcharles — the gateway busy-session/queue
infrastructure was rewritten since that PR (Telegram moved to
plugins/platforms/, /queue now uses the FIFO chain), so the media fix is
reimplemented against the current handler; the PR's batching and
busy-bypass changes targeted code paths that no longer exist.

Co-authored-by: ypwcharles <92324143+ypwcharles@users.noreply.github.com>
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
/queue rebuilt the queued MessageEvent with only text/type/source/
message_id/channel_prompt, silently dropping any photo, document, voice,
or reply context attached to the command. The deferred turn then ran with
the attachment lost. Carry the full payload through, and accept a /queue
that has media but no prompt text (e.g. "/queue" as an image caption).

Salvaged from NousResearch#13913 by @ypwcharles — the gateway busy-session/queue
infrastructure was rewritten since that PR (Telegram moved to
plugins/platforms/, /queue now uses the FIFO chain), so the media fix is
reimplemented against the current handler; the PR's batching and
busy-bypass changes targeted code paths that no longer exist.

Co-authored-by: ypwcharles <92324143+ypwcharles@users.noreply.github.com>
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
/queue rebuilt the queued MessageEvent with only text/type/source/
message_id/channel_prompt, silently dropping any photo, document, voice,
or reply context attached to the command. The deferred turn then ran with
the attachment lost. Carry the full payload through, and accept a /queue
that has media but no prompt text (e.g. "/queue" as an image caption).

Salvaged from NousResearch#13913 by @ypwcharles — the gateway busy-session/queue
infrastructure was rewritten since that PR (Telegram moved to
plugins/platforms/, /queue now uses the FIFO chain), so the media fix is
reimplemented against the current handler; the PR's batching and
busy-bypass changes targeted code paths that no longer exist.

Co-authored-by: ypwcharles <92324143+ypwcharles@users.noreply.github.com>
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 sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants