# Telegram Unified Tooling Architecture

Goal: give Telegram-sourced agent runs one scoped `telegram` tool that covers
Telegram Bot API operations behind explicit Omnius policy, Telegram bot rights,
and admin-controlled toggles. This replaces the current drift where some
Telegram powers exist as private helpers, some exist as TUI slash commands, and
only `telegram_send_file` is model-facing.

## Current State

The bot does not currently expose message deletion as an agent tool.

Existing code paths:

- `packages/cli/src/tui/telegram-bridge.ts`
  - `deleteLiveMessage(...)` is a private cleanup helper for Omnius streaming
    messages. It calls `deleteMessage`, but it is not a model-facing tool and
    cannot be used for janitorial moderation.
  - `deleteMessageReaction(...)` and `deleteAllMessageReactions(...)` exist as
    bridge methods.
  - `getChatAdministrators(...)` exists as a bridge method.
  - `sendCallButton(...)` sends an inline URL keyboard, but the bridge does not
    poll `callback_query` updates and does not answer callback queries.
  - `buildSubAgentTools(...)` exposes `telegram_send_file`, not a unified
    Telegram admin/moderation tool.
- `packages/cli/src/tui/commands.ts`
  - `/telegram delete-reaction ...`
  - `/telegram delete-reactions ...`
  - `/telegram admins ...`
  - No `/telegram delete-message` or `/telegram delete-messages`.
- `packages/cli/src/tui/tool-policy.ts`
  - Whole-tool context gating exists.
  - There is no action-level policy for one high-scope Telegram tool.

Result: Omnius can send files and delete reactions, but it cannot agentically
delete its own messages or user messages. It also cannot offer Telegram inline
buttons for scoped tool enable/disable because callback queries are not wired.

## Official API Constraints

Sources:

- https://core.telegram.org/bots/api#deletemessage
- https://core.telegram.org/bots/api#deletemessages
- https://core.telegram.org/bots/api#getchatadministrators
- https://core.telegram.org/bots/api#callbackquery
- https://core.telegram.org/bots/api#answercallbackquery
- https://core.telegram.org/bots/api#inlinekeyboardmarkup

Deletion constraints to model explicitly:

- Bots can delete outgoing messages in private chats, groups, and supergroups.
- Bots can delete incoming messages in private chats.
- In groups, a bot must be an administrator to delete arbitrary messages.
- In supergroups/channels, the bot needs `can_delete_messages` to delete
  arbitrary messages.
- Telegram applies message-age and service-message limits. Failed deletes must
  report the Bot API error back to the tool result.
- `deleteMessages` is the batch endpoint for multiple message IDs and should be
  preferred when deleting more than one message.

Inline button constraints:

- The poll loop must request `callback_query` updates.
- Every callback query should be answered with `answerCallbackQuery`, even when
  no alert is shown, so Telegram clients stop the progress spinner.
- Callback payloads are limited and should carry only a short signed state key
  or compact action token, not full policy JSON.

## Target Shape

Expose one model-facing tool:

```text
telegram({
  action: "...",
  target: "...",
  message_id: 123,
  message_ids: [123, 124],
  user_id: 777,
  permissions: {...},
  text: "...",
  reason: "...",
  dry_run: false
})
```

Keep `telegram_send_file` as a compatibility alias for now, but route it through
the same underlying delivery ledger and policy checks.

### Action Groups

Read actions:

- `get_me`
- `get_chat`
- `get_chat_member`
- `get_chat_administrators`
- `get_message_context`
- `get_tool_scope`

Message actions:

- `send_message`
- `edit_message_text`
- `edit_message_caption`
- `edit_message_reply_markup`
- `delete_message`
- `delete_messages`
- `pin_message`
- `unpin_message`
- `unpin_all_messages`

Media actions:

- `send_file`
- `send_photo`
- `send_document`
- `send_audio`
- `send_voice`
- `send_video`

Moderation actions:

- `ban_chat_member`
- `unban_chat_member`
- `restrict_chat_member`
- `promote_chat_member`
- `set_chat_permissions`
- `approve_chat_join_request`
- `decline_chat_join_request`

Reaction actions:

- `set_message_reaction`
- `delete_message_reaction`
- `delete_all_message_reactions`

Bot and admin actions:

- `set_my_commands`
- `get_my_commands`
- `set_chat_menu_button`
- `get_chat_menu_button`
- `set_my_description`
- `get_my_description`

Policy actions:

- `scope_status`
- `enable_action`
- `disable_action`
- `enable_group`
- `disable_group`
- `render_admin_buttons`

## Scope Model

The `telegram` tool should evaluate four layers before making any Bot API call.

1. Telegram source context

- `telegram-public`: current chat only. No janitorial or moderation actions.
- `telegram-admin-group`: current chat only. Janitorial actions allowed only if
  the Omnius policy enables them and the sender is the authenticated admin.
- `telegram-admin-dm`: may target the current DM or a known prior chat from the
  bridge target registry. Unknown numeric chat IDs are allowed only when the
  local admin explicitly supplies them.

2. Omnius action policy

Add action-level policy below the current whole-tool policy:

```ts
interface TelegramToolPolicy {
  enabledActionGroups?: Record<string, boolean>;
  enabledActions?: Record<string, boolean>;
  chatOverrides?: Record<string, {
    enabledActionGroups?: Record<string, boolean>;
    enabledActions?: Record<string, boolean>;
  }>;
  requireAdminForMutation?: boolean;
  dryRunByDefault?: boolean;
}
```

Persist this under `OmniusSettings.telegramToolPolicy`.

3. Bot rights

Before mutating chat state, call or cache bot rights:

- `getMe` for bot id.
- `getChatMember(chat_id, bot_id)` or `getChatAdministrators(chat_id, true)`.
- Require `can_delete_messages` before `delete_message(s)` for supergroups and
  channels.
- Require matching rights for pinning, restricting, banning, promotion, and
  permissions changes.

4. Operation proof

Mutating tool results should include:

- `action`
- `chat_id`
- `message_id` or `message_ids`
- `telegram_method`
- `ok`
- `bot_rights_checked`
- `policy_scope`
- Telegram error description if failed

## Admin Buttons

Add a Telegram admin control surface using inline keyboards.

Command routes:

- `/telegram tools` in TUI: print current policy and optionally send a Telegram
  admin panel to the admin DM.
- `/tools` or `/telegram_tools` in Telegram admin DM: show buttons.
- `/telegram tools group <chat>`: show/edit policy for a group.

Button behavior:

- Add `callback_query` to `allowed_updates` in `pollLoop`.
- Normalize callback updates beside messages.
- Add `handleTelegramCallbackQuery(...)`.
- Verify callback sender is the authenticated admin.
- Call `answerCallbackQuery` for every callback.
- Store button state server-side:
  - `.omnius/telegram-tool-buttons/<nonce>.json`
  - callback payload: `omni:v1:tool:<nonce>:<action>`
  - short TTL, e.g. 15 minutes.
- Toggle action groups or actions, then edit the menu message with updated
  checkboxes.

Suggested panels:

- Global policy:
  - Read
  - Message send/edit
  - Janitorial delete
  - Reactions
  - Moderation
  - Bot profile/admin
- Current chat override:
  - Same groups, but scoped to one chat id.
- Safety buttons:
  - Dry-run by default on/off.
  - Require admin confirmation for delete-many/moderation on/off.

## Code Anchors

Primary implementation anchors:

- `packages/cli/src/tui/telegram-bridge.ts`
  - Add `buildTelegramTool(context, repoRoot, chatId, msg)`.
  - Register this tool in `buildSubAgentTools(...)`.
  - Replace direct action helpers with shared `callTelegramApiAction(...)`.
  - Add public bridge methods:
    - `deleteTelegramMessage(...)`
    - `deleteTelegramMessages(...)`
    - `getChatMember(...)`
    - `getBotChatRights(...)`
    - `answerCallbackQuery(...)`
    - `sendTelegramToolPanel(...)`
    - `handleTelegramCallbackQuery(...)`
  - Add `callback_query` to `allowed_updates`.
- `packages/cli/src/tui/tool-policy.ts`
  - Add `telegram` to safe allowlists only for read/status actions.
  - Keep high-risk behavior inside action-level policy.
- `packages/cli/src/tui/omnius-directory.ts`
  - Add `telegramToolPolicy?: TelegramToolPolicy`.
- `packages/cli/src/tui/commands.ts`
  - Add `/telegram tools`.
  - Add `/telegram delete-message <chat> <message_id>`.
  - Add `/telegram delete-messages <chat> <message_id,...>`.
- `packages/cli/src/tui/interactive.ts`
  - Wire settings save/load and bridge policy updates.
- `packages/cli/tests/telegram-bot-api-10.test.ts`
  - Add coverage for message deletion, batch deletion, callback query toggles,
    policy denials, and bot-rights denials.
- `README.md`
  - Document the unified `telegram` tool, policy defaults, and button controls
    after implementation.

## Default Policy Recommendation

Defaults should be conservative:

- `telegram-public`
  - allow read-only context actions only.
  - deny deletion, moderation, bot profile, and arbitrary target sends.
- `telegram-admin-group`
  - allow `delete_message` only for current chat when the target message is the
    bot's own message by default.
  - require explicit policy enablement for deleting user messages.
  - deny moderation by default.
- `telegram-admin-dm`
  - allow full read and send actions.
  - allow janitorial actions only after explicit enablement.
  - allow moderation only after explicit enablement and bot-rights confirmation.

## Implementation Checklist

- [x] Add `TelegramToolPolicy` settings type and load/save plumbing.
- [x] Add `telegram` action tool with scoped target resolution.
- [x] Add delete single/batch message bridge methods.
- [x] Add bot-rights introspection and cache.
- [x] Register `telegram` in Telegram admin DM, admin group, and public contexts.
- [x] Add action-level policy enforcement before each Bot API call.
- [x] Keep `telegram_send_file` as alias/wrapper over `telegram(action=send_file)`.
- [x] Add TUI slash routes for delete-message(s) and tools policy.
- [x] Add callback query polling and `answerCallbackQuery`.
- [x] Add inline keyboard policy panel for admin toggles.
- [x] Add tests for allowed deletes, denied deletes, rights failures, and callback
      toggles.
- [x] Update README once behavior is real.

## Done Criteria

This is complete when:

1. An admin DM can ask the agent to delete a bot message or user message in a
   known group, and the model calls `telegram(action="delete_message", ...)`.
2. A public group user cannot cause deletion unless the sender is authenticated
   admin, the action is enabled, the target is in the current chat, and the bot
   has Telegram rights.
3. The admin can open Telegram inline buttons to enable/disable action groups.
4. The same policy can be changed from TUI slash commands.
5. Tool results show enough provenance to audit what happened.
