Skip to content

feat(messages): inline-button support (buttons/click) and live latest#11

Open
zhiyue wants to merge 3 commits into
dgrr:mainfrom
zhiyue:feat/inline-buttons-callback
Open

feat(messages): inline-button support (buttons/click) and live latest#11
zhiyue wants to merge 3 commits into
dgrr:mainfrom
zhiyue:feat/inline-buttons-callback

Conversation

@zhiyue

@zhiyue zhiyue commented Jun 24, 2026

Copy link
Copy Markdown

What

Adds three messages subcommands, built on grammers' raw API, so tgcli can drive bots that reply with inline keyboards (e.g. search bots that send a file when you tap a result):

Command Purpose
messages buttons --chat <id> --message <id> List a message's inline keyboard — index, kind, callback data (base64) / url — read live via Message::reply_markup().
messages click --chat <id> --message <id> --button <idx> Press a callback button via messages.getBotCallbackAnswer. Select by --button <index> or raw --data <base64>. With --wait <secs> / --download [--dest <path>] it polls for the bot's follow-up message and downloads its media.
messages latest --chat <id> --limit <n> Fetch the newest messages straight from Telegram, bypassing the local DB — a live view without a prior sync.

Why

grammers exposes received buttons through Message::reply_markup() but has no high-level "click"; the actual press needs the raw messages.getBotCallbackAnswer. This wires that up so the CLI can complete flows like search bot → pick a result → receive the file that previously required the official app.

Notes

  • Bots that do heavy work (fetching a file) often don't answer the callback within Telegram's window, surfacing BOT_RESPONSE_TIMEOUT. tgcli treats this as delivered and still waits for the follow-up message when --wait/--download is set.
  • New code is isolated in src/app/buttons.rs; the only change to existing code is making App::resolve_peer_ref pub(crate) plus the command wiring and README docs.
  • cargo build, cargo build --release, and cargo fmt are all clean.

Verification

End-to-end against a live search bot: /s <book>messages latest (get the results message id) → messages buttonsmessages click the preview button → messages buttonsmessages click the download button with --download → file auto-downloaded and verified (valid EPUB).

https://claude.ai/code/session_016T92jG6xyYALWQfuaUaB82

Add three `messages` subcommands built on grammers' raw API so the CLI
can drive bots that reply with inline keyboards (e.g. search bots that
deliver a file when you tap a result):

- `messages buttons`  list a message's inline keyboard (index, kind,
  callback data / url), read live via `Message::reply_markup()`.
- `messages click`    press a callback button via
  `messages.getBotCallbackAnswer`, selecting by `--button <index>` or
  raw `--data <base64>`; with `--wait`/`--download` it then polls for
  the bot's follow-up message and downloads its media.
  `BOT_RESPONSE_TIMEOUT` is treated as delivered (slow bots still act
  on the press).
- `messages latest`   fetch the newest messages straight from Telegram,
  bypassing the local DB (a live view without a prior `sync`).

Implementation: new `src/app/buttons.rs` (parses `ReplyInlineMarkup`
into a flat, indexable button list, plus click + wait/download helpers);
`App::resolve_peer_ref` made `pub(crate)`; README updated.

Verified end-to-end against a live search bot:
/s <book> -> latest -> buttons -> click bookpreview -> buttons -> click
download -> file auto-downloaded (valid EPUB).

Claude-Session: https://claude.ai/code/session_016T92jG6xyYALWQfuaUaB82
Copilot AI review requested due to automatic review settings June 24, 2026 09:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds new tgcli messages functionality to support bot inline keyboards (list buttons, click callback buttons, and fetch latest messages directly from Telegram) using grammers raw TL API where needed.

Changes:

  • Introduces messages buttons, messages click, and messages latest CLI subcommands and wires them into command dispatch/output formatting.
  • Adds src/app/buttons.rs implementing inline keyboard extraction, callback “click” via messages.getBotCallbackAnswer, optional polling for follow-up messages, and optional media downloading.
  • Exposes App::resolve_peer_ref as pub(crate) so the new app module can resolve chat peers for raw API calls.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/cmd/messages.rs Adds new subcommands and human/JSON output for buttons/click/latest.
src/app/send.rs Makes resolve_peer_ref pub(crate) for cross-module reuse.
src/app/mod.rs Registers the new buttons app module.
src/app/buttons.rs Implements button listing, callback clicking, follow-up polling, and download integration.
README.md Documents the new inline button/bot workflow commands.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/cmd/messages.rs Outdated
Comment thread src/app/buttons.rs
Comment thread src/app/buttons.rs
Comment thread src/app/buttons.rs Outdated
Comment thread src/app/buttons.rs Outdated
- buttons: show the base64 callback payload (copy-pasteable into
  `messages click --data`), appending the decoded text when printable,
  instead of only the decoded text.
- click: fetch the origin message up front so `msg_id` is validated even
  on the --data path, and capture its sender to filter follow-ups.
- wait_for_new_messages: keep only messages from the origin sender (so a
  busy group's other messages aren't mistaken for the bot's reply) and
  widen the per-poll window from 10 to 50 to avoid missing follow-ups.
- de-duplicate the "fetch one message by id" logic into a shared
  App::fetch_message_by_id, reused by download_media and the button commands.

Addresses the automated review comments on dgrr#11.

Claude-Session: https://claude.ai/code/session_016T92jG6xyYALWQfuaUaB82
@zhiyue

zhiyue commented Jun 24, 2026

Copy link
Copy Markdown
Author

Thanks for the review! Pushed c2df11d addressing all five comments:

  • buttons: print the base64 callback payload (copy-pasteable into messages click --data), appending the decoded text when printable.
  • click: fetch the origin message up front (validates msg_id even on the --data path) and capture its sender.
  • wait_for_new_messages: keep only follow-ups from the origin sender, so other users' messages in a group aren't mistaken for the bot's reply.
  • poll window: 10 → 50 per poll to avoid missing follow-ups.
  • dedup: extracted a shared App::fetch_message_by_id, reused by download_media and the button commands.

cargo build, cargo clippy, and cargo fmt are clean. Verified end-to-end against a search bot (search → list buttons → click → auto-download).

60 chars truncated useful content — e.g. a search bot's results listing
where each item's format/size/rating lives past the first line. Show the
full message (bounded at 4000 to avoid dumping pathological messages) so
callers can read/filter it (pick by TXT/EPUB, etc.).

Claude-Session: https://claude.ai/code/session_016T92jG6xyYALWQfuaUaB82
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants