Skip to content

Telegram plugin

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: 14 total; see the complete catalog below
  • ingress adapter:
  • telegram.update
  • poller:
  • telegram.updates

Supported actions: complete catalog

The Telegram plugin currently registers 14 actions. This list is intended to be the authoritative enumeration of the supported Call Baxter Telegram action surface.

Messaging and media

Action Purpose Required args Optional args
telegram.send_message Send a text message. Also serves as the normal reply/respond action. chat_id, text reply_to_message_id, reply_markup
telegram.send_photo Upload and send a photo. chat_id, filename, data caption
telegram.send_document Upload and send a document. chat_id, filename, data caption

For telegram.send_photo and telegram.send_document, data is a latin-1 string whose code points represent the original byte values. This matches the binary-string convention used by other Call Baxter plugin actions.

There is no separate reply action because a Telegram reply is a normal telegram.send_message with reply_to_message_id set:

- kind: telegram.send_message
  args:
    chat_id: "{{ event.attrs.chat_id }}"
    reply_to_message_id: "{{ event.attrs.message_id }}"
    text: "Received."

Message mutation and moderation

Action Purpose Required args Optional args
telegram.edit_message_text Edit a bot-authored text message in place. chat_id, message_id, text reply_markup
telegram.set_message_reaction Set an emoji reaction on a message. chat_id, message_id, emoji is_big
telegram.delete_message Delete a message when the bot has permission. chat_id, message_id —
telegram.pin_chat_message Pin a message when the bot has permission. chat_id, message_id disable_notification
telegram.unpin_chat_message Unpin a specific message. chat_id, message_id —

Example reaction rule action:

- kind: telegram.set_message_reaction
  args:
    chat_id: "{{ event.attrs.chat_id }}"
    message_id: "{{ event.attrs.message_id }}"
    emoji: "👍"

Callback and structured operator interaction

Action Purpose Required args Optional args
telegram.answer_callback_query Acknowledge/respond to an inline-keyboard callback query. callback_query_id text, show_alert
telegram.request_decision Send a deterministic multi-option decision prompt with inline buttons. chat_id, text, correlation_id, source, options timeout_seconds, default_action, reply_to_message_id
telegram.request_confirmation Send an auditable approve/reject confirmation prompt. chat_id, text, correlation_id, source timeout_seconds, default_action, approve_label, reject_label, reply_to_message_id
telegram.send_progress Send a structured progress/phase tracker message. chat_id, title, phases, current_phase status, detail, reply_to_message_id
telegram.update_progress Update an existing structured progress tracker in place. chat_id, message_id, title, phases, current_phase status, detail

Projection/storage

Action Purpose Required args Optional args
telegram.persist_update Persist a raw Telegram update into the tg-agent-cli projection database. database_url, update bot_ref, source, bot_token, api_base, media_storage_mode, media_base_dir

The first 13 actions above mutate Telegram remotely and therefore use Call Baxter's external/non-idempotent action execution contract. telegram.persist_update is a projection/storage action and has a separate execution contract.

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 messaging, replies, media, reactions, edits, deletion, pinning, callbacks, confirmations, decisions, and progress/status messages
  • 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