Skip to content

feat(gateway): Telegram session-picker with inline resume buttons and recap context - #75469

Open
immeasurablematt wants to merge 2 commits into
NousResearch:mainfrom
immeasurablematt:local/telegram-session-picker-resume
Open

feat(gateway): Telegram session-picker with inline resume buttons and recap context#75469
immeasurablematt wants to merge 2 commits into
NousResearch:mainfrom
immeasurablematt:local/telegram-session-picker-resume

Conversation

@immeasurablematt

Copy link
Copy Markdown

What

Adds inline choice buttons for Telegram DM session listing (/sessions and /sessions all) with per-session resume recaps showing last user message, assistant response, and age. Improves the mobile session-resume UX by keeping context visible before the user commits to resuming a session.

Changes

  • _format_telegram_sessions_picker — renders numbered context above narrow mobile-safe buttons with per-session latest-user-message excerpts
  • _format_telegram_resume_recap — adds visible 'Where you left off' context after a picker-triggered resume, showing last user question + where the assistant left off
  • _resume_recap_snippet / _resume_recap_age / _latest_user_context — compact helpers for excerpt formatting, relative timestamps, and reply-quotation stripping
  • Integration in /sessions command — Telegram DMs get the inline picker path (guarded by chat_type == "dm" to preserve the session-ownership boundary; group chats and non-Telegram platforms keep the existing text listing)
  • Adapter patch — passes metadata through send_choice_picker for correct thread routing
  • Tests — exercise picker formatting output, recap age rendering (just now / minutes / hours / days / dates), and user-context extraction with reply-quotation stripping

Why

Currently, /sessions on Telegram returns a dense text list. In a DM, the user has to copy a session ID and paste it into /resume <id>. The inline picker replaces that with numbered context + tap-to-resume buttons — the same number of taps but with context the user can read before committing.

Scope

Telegram DMs only — the chat_type == "dm" guard keeps session-ownership boundaries intact. Other platforms and group chats are unaffected.

… recap context

Adds inline choice buttons for Telegram DM session listing with per-session
resume recaps showing last user message, assistant response, and age. Improves
the mobile session-resume UX by keeping context visible before the user
commits to resuming a session.

- _format_telegram_sessions_picker: renders numbered context above narrow
  mobile-safe buttons with per-session latest-user-message excerpts
- _format_telegram_resume_recap: adds visible 'Where you left off' context
  after a picker-triggered resume
- _resume_recap_snippet / _resume_recap_age / _latest_user_context helpers
- Integration in /sessions command: Telegram DMs get the inline picker path
  (chat_type=dm guard preserves session ownership boundary)
- Adapter patch: pass metadata through send_choice_picker for thread routing
- Tests: exercise picker formatting, recap age rendering, and user-context
  extraction with reply-quotation stripping
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter 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 labels Jul 31, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the Telegram DM resume UX improvement. The feature addresses a current gap: main still returns the text session listing at gateway/slash_commands.py:4525-4529.

Problems

  • The resume picker is unsafe to reuse through the current generic Telegram picker state. The adapter stores one state object per chat at plugins/platforms/telegram/adapter.py:5664-5668, but resolves cp:<index> from that current state at plugins/platforms/telegram/adapter.py:5700-5711 without checking the callback message id. After a user opens a second /sessions picker, tapping a button on the first visible message can resume the session at the matching index from the newer picker.
  • The new tests mock send_choice_picker (tests/gateway/test_resume_command.py:106-108) and directly invoke the closure, so they do not cover the Telegram callback/state-replacement path.

Suggested changes

  • Bind picker state to the sent message id or a callback token and reject stale-message callbacks before invoking the resume closure registered at gateway/slash_commands.py:4701.
  • Add a regression test for two pickers in one chat followed by a tap on the first message.

This is an automated hermes-sweeper review.

Comment thread gateway/slash_commands.py
),
choices=choices,
session_key=current_entry.session_key,
on_choice_selected=_resume_from_picker,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This registers a session-switching closure in the generic picker, but Telegram keeps only one _choice_picker_state[chat_id]. Its callback handler does not validate state['msg_id'] against the clicked message, so after a second /sessions picker replaces state, a tap on the older visible picker resolves an index from the newer list and can resume the wrong session. Bind state to the picker message/token and reject stale callbacks; add a two-picker regression test.

@teknium1 teknium1 added sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users area/sessions Session lifecycle, resume, persistence, history labels Jul 31, 2026
…s-talk

Previously _choice_picker_state was keyed by chat_id alone, so opening a
second picker in the same chat overwrote the first picker's state. Tapping
a button on the first (still-visible) message would then resolve from the
second picker's indices — a wrong session could resume.

Now keyed as chat_id:message_id, so each picker message carries its own
isolated state. Stale-message callbacks whose state has been cleaned up
receive the 'Picker expired' answer instead of resolving from a newer
picker's closure.

- send_choice_picker: key on f"{chat_id}:{msg.message_id}"
- _handle_choice_picker_callback: resolve state_key from query.message.message_id
- Regression test: two pickers, same chat, verify independent closures
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

Five PRs address the Telegram session-navigation UX gap: #33702 and #33725 target a button-based bare /resume, #43695 adds a separate /sessions picker with a new-session action, #49038 adds a paginated /resume picker, and #75469 adds a Telegram-DM /sessions picker with contextual recaps and message-bound state.

Related pull requests

Duplicates

#33725 is the empty scoped resubmission of #33702. #43695 and #49038 substantially overlap with #75469 on Telegram inline session selection and are superseded by its current-plugin, DM-scoped, message-bound approach; #33702 is an earlier /resume-specific predecessor with unrelated cron scope.

Suggested consolidation

Keep #75469 open with a salvage path: retain its contextual Telegram-DM picker, existing /resume authorization path, and chat_id:message_id state binding, but require a two-picker regression test that invokes _handle_choice_picker_callback and proves that clicking the older message selects only its own session. Close #43695 as a duplicate of #75469 despite its keep_open review because its diff still uses the obsolete adapter location and retains ownership and stale-keyboard hazards; close #49038 as a duplicate of #75469 despite its keep_open review because its unique pagination is coupled to an unauthenticated callback, obsolete switching logic, chat-only state, and no tests. #33702 and #33725 should remain closed as superseded predecessors.

Cross-PR triage: Reviewed 5 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 81 kB of PR diffs, 7 kB of issue/PR text, 5 kB of discussion (5 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have platform/telegram Telegram bot adapter sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users 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/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants