Skip to content

Telegram plugin sketch

The Telegram plugin in this scaffold contributes:

  • event definitions:
  • telegram.message.new
  • telegram.message.edited
  • telegram.channel_post.new
  • telegram.channel_post.edited
  • telegram.business_message.new
  • telegram.business_message.edited
  • telegram.callback_query.new
  • telegram.media.present
  • telegram.message.reaction
  • action definitions:
  • telegram.send_message
  • telegram.answer_callback_query
  • telegram.persist_update
  • ingress adapter:
  • telegram.update
  • poller:
  • telegram.updates

Why this matters

If the runtime already exposes HTTP ingress, a Telegram webhook can hit the callback runtime directly. That means a dedicated Telegram daemon is no longer required for event-driven automation.

Webhook ingress and polling both flow through the same Telegram plugin update pipeline:

raw update
  -> optional projection persistence into tg-agent-cli db
  -> normalized telegram.* events
  -> generic call-baxter rule matching

What telegram.callback_query.new does

This event represents an incoming callback query, typically triggered by a user pressing an inline keyboard button. It carries:

  • callback_query_id
  • callback_ref
  • callback data
  • optional from_user_id
  • the raw update payload
  • optional originating chat_ref / message_ref

That makes it the event to match when you want to:

  • answer the callback query
  • branch on button payload data
  • correlate the button press with the message that contained the inline keyboard

Message events also expose optional from_is_bot. This is useful when a callback update includes the original bot-authored message and a rule must avoid recursively processing that synthetic parent message.

Inline keyboards

telegram.send_message accepts an optional structured reply_markup object. For example:

- kind: telegram.send_message
  args:
    chat_id: "{{ event.attrs.chat_id }}"
    text: Choose an action
    reply_markup:
      inline_keyboard:
        - - text: Status
            callback_data: cmd:status

The Telegram API client also accepts a JSON string for compatibility, validates that it decodes to an object, and sends it as a JSON object in the Bot API request.

The client validates Telegram text boundaries before making a request:

  • telegram.send_message requires 1–4096 characters;
  • telegram.answer_callback_query accepts at most 200 characters.

This makes invalid rules fail as audited action results locally instead of depending on a remote Bot API rejection.

What can move into call-baxter

Good fits for the generic runtime:

  • webhook ingestion of raw Telegram updates
  • getUpdates polling through the Telegram poller
  • normalization of updates into events
  • outbound actions like sendMessage and answerCallbackQuery
  • YAML rules reacting to normalized message or callback-query events

Still valuable as a source-specific projection when needed:

  • rich browse-first chat history UI
  • Telegram-specific media storage policies
  • advanced message/thread/entity indexing
  • high-fidelity Bot API coverage across all update and media variants

So the pragmatic split is:

  • use call-baxter as the event runtime and control plane
  • keep tg-agent-cli as a separate browse/projection tool
  • let the Telegram plugin persist into the Telegram projection DB directly when configured
  • keep telegram.persist_update available as an explicit action for unusual flows